#include #include "microcobs.h" #include "crc32.h" struct __attribute__((packed)) ll_pkt_trailer { uint32_t crc32; }; struct __attribute__((packed)) req_pkt { uint32_t req_seq; struct ll_pkt_trailer trailer; }; struct __attribute__((packed)) res_pkt { uint32_t req_seq; uint32_t res_seq; struct ll_pkt_trailer trailer; }; struct tx_state { uint8_t *tx_char; int remaining_bytes; }; static crc32_t pkt_crc(void *pkt, struct ll_pkt_trailer *trailer); crc32_t pkt_crc(void *pkt, struct ll_pkt_trailer *trailer) { crc32_t crc = crc32_reset(); for (uint8_t *in = (uint8_t *)pkt; in < (uint8_t *)trailer; in++) { crc = crc32_update(crc, *in); } return crc32_finalize(crc); } static void packetize(void *pkt, struct ll_pkt_trailer *trailer); void packetize(void *pkt, struct ll_pkt_trailer *trailer) { trailer->crc32 = pkt_crc(pkt, trailer); } enum mems_regs { MEMS_REG_CTRL0, /* 0 */ MEMS_REG_CTRL1, /* 1 */ MEMS_REG_CONFIG, /* 2 */ MEMS_REG_STATUS0, /* 3 */ MEMS_REG_STATUS1, /* 4 */ MEMS_REG_STATUS2, /* 5 */ MEMS_REG_CHIP_REVID, /* 6 */ MEMS_REG_ACC_CHX_LOW, /* 7 */ MEMS_REG_ACC_CHX_HIGH, /* 8 */ MEMS_REG_ACC_CHY_LOW, /* 9 */ MEMS_REG_ACC_CHY_HIGH, /* 10 */ MEMS_REG_OSC_COUNTER, /* 11 */ MEMS_REG_ID_SENSOR_TYPE, /* 12 */ MEMS_REG_ID_VEH_MANUF, /* 13 */ MEMS_REG_ID_SENSOR_MANUF, /* 14 */ MEMS_REG_ID_LOT0, /* 15 */ MEMS_REG_ID_LOT1, /* 16 */ MEMS_REG_ID_LOT2, /* 17 */ MEMS_REG_ID_LOT3, /* 18 */ MEMS_REG_ID_WAFER, /* 19 */ MEMS_REG_ID_COOR_X, /* 20 */ MEMS_REG_ID_COOR_Y, /* 21 */ MEMS_REG_RESET, /* 22 */ MEMS_REG_OFF_CHX_HIGH, /* 23 */ MEMS_REG_OFF_CHX_LOW, /* 24 */ MEMS_REG_OFF_CHY_HIGH, /* 25 */ MEMS_REG_OFF_CHY_LOW, /* 26 */ }; uint8_t crc8_calc(uint8_t *data, size_t len) { int acc = 0; for (size_t i=0; i>= 1; } } return acc; } uint32_t mems_trx_word(uint32_t data) { /* CAUTION: ST's SPI peripherals behave differently depending on DR register access size, yet the CMSIS headers * expose it as an 32-bit uint only. In this case, we actually want a 32-bit access. */ uint16_t *dr = (uint16_t *)&SPI1->DR; *dr = data>>16; while (SPI1->SR & SPI_SR_BSY) ; uint32_t out = (*dr) << 16; *dr = data&0xffff; while (SPI1->SR & SPI_SR_BSY) ; out |= *dr; return out; } uint32_t mems_trx_cmd(uint32_t cmd) { GPIOA->BRR = 1<<15; /* De-assert !CS */ uint8_t bytes[3] = {(cmd>>16)&0xff, (cmd>>8)&0xff, cmd&0xff}; uint8_t crc = crc8_calc(bytes, 3); int parity = !!parity_calc(bytes, 3); uint32_t out = mems_trx_word(cmd | (parity<BSRR = 1<<15; /* Assert !CS */ return out; } void mems_write_reg(int addr, int val) { addr &= MEMS_ADDR_Msk; val &= MEMS_DATA_Msk; (void)mems_trx_cmd((1<> MEMS_DATA_Pos) & MEMS_DATA_Msk; } int16_t mems_read_meas(int ch) { ch &= 3; mems_trx_cmd((ch<> MEMS_MEAS_Pos) << 2; /* Now do an arithmetic division to sign extend */ return data / 4; } void mems_spi_init(void) { SPI1->CR1 = (6<CR2 = (15<CR1 |= SPI_CR1_SPE; } void mems_init(void) { mems_spi_init(); for (size_t i=0; i<10000; i++) { asm volatile("nop"); } /* Take accelerometer out of initialization phase */ mems_write_reg(MEMS_REG_CTRL0, 0x01); } int main(void) { RCC->AHBENR |= RCC_AHBENR_GPIOAEN; RCC->APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2ENR_SPI1EN; #define AFRL(pin, val) ((val) << ((pin)*4)) #define AFRH(pin, val) ((val) << (((pin)-8)*4)) #define AF(pin) (2<<(2*(pin))) #define OUT(pin) (1<<(2*(pin))) #define IN(pin) (0) #define ANALOG(pin) (3<<(2*(pin))) #define CLEAR(pin) (3<<(2*(pin))) /* GPIO pin config: * A9: USART 1 TX -> LED * A10: USART 1 RX -> debug * A15: Accelerometer CS * A5/6/7: SPI SCK/MISO/MOSI for Accelerometer */ GPIOA->MODER &= ~(CLEAR(15)); /* Clear JTAG TDI pin mode */ GPIOA->MODER |= AF(9) | AF(10) | OUT(15) | AF(5) | AF(6) | AF(7); GPIOA->AFR[0] = AFRL(5, 5) | AFRL(6, 5) | AFRL(7, 5); GPIOA->AFR[1] = AFRH(9, 7) | AFRH(10, 7); GPIOA->BSRR = 1<<15; /* De-assert accelerometer !CS */ SystemCoreClockUpdate(); int apb2_clock = SystemCoreClock / APB2_PRESC; int baudrate = 115200; USART1->CR1 = USART_CR1_TE | USART_CR1_RE; USART1->BRR = (apb2_clock + baudrate/2) / baudrate; USART1->CR2 |= USART_CR2_RXINV; //| USART_CR2_TXINV; USART1->CR1 |= USART_CR1_UE; /* FIXME DEUBG */ while (1) { mems_init(); for (int i=0; i<100000; i++) asm volatile("nop"); for (int i=0; i<300; i++) { mems_read_meas(0); //mems_read_reg(MEMS_REG_ID_SENSOR_TYPE); for (int i=0; i<10000; i++) asm volatile("nop"); } for (int i=0; i<100000; i++) asm volatile("nop"); } int req_seq = 0; int res_seq = 0; struct req_pkt req_buf = { 0 }; struct tx_state tx_st = { 0 }; struct res_pkt res_buf = { 0 }; uint8_t rx_buf[512]; uint8_t tx_buf[512]; size_t rx_char = 0; unsigned int rx_overrun = 0; unsigned int rx_cobs_error = 0; unsigned int rx_framing_error = 0; unsigned int rx_crc_error = 0; USART1->TDR = 0; /* Kick off transmission */ int i = 0; while (23) { if (tx_st.remaining_bytes == 0) { if (i > 100) { res_buf.req_seq = req_seq; res_buf.res_seq = res_seq; res_seq += 1; packetize(&res_buf, &res_buf.trailer); tx_st.tx_char = tx_buf; tx_st.remaining_bytes = cobs_encode((uint8_t *)&res_buf, sizeof(res_buf), tx_buf, sizeof(tx_buf));; /* for (int k=0; k < 8; k++) tx_buf[k] = 255-k; for (int k=0; k < 8; k++) tx_buf[8+k] = (k + 1) % 8; tx_st.remaining_bytes = 16; */ i = 0; } else { i++; } } if (USART1->ISR & USART_ISR_TXE && tx_st.remaining_bytes > 0) { USART1->TDR = *(tx_st.tx_char); tx_st.tx_char += 1; tx_st.remaining_bytes -= 1; } if (USART1->ISR & USART_ISR_ORE) USART1->ICR = USART_ICR_ORECF; if (USART1->ISR & USART_ISR_NE) USART1->ICR = USART_ICR_NCF; if (USART1->ISR & USART_ISR_FE) USART1->ICR = USART_ICR_FECF; if (USART1->ISR & USART_ISR_RXNE) { uint8_t c = USART1->RDR; if (!c) { if (rx_char < sizeof(rx_buf)) { int rc = cobs_decode(rx_buf, rx_char, (uint8_t *)&req_buf, sizeof(req_buf)); if (rc < 0) { rx_cobs_error += 1; } else { if (rc == sizeof(req_buf)) { crc32_t check_crc = pkt_crc(&req_buf, &req_buf.trailer); if (check_crc != req_buf.trailer.crc32 || check_crc == 0 || (int)check_crc == -1) { rx_crc_error += 1; } else { req_seq = req_buf.req_seq; } } else { rx_framing_error += 1; } } } rx_char = 0; } else { if (rx_char < sizeof(rx_buf)) { rx_buf[rx_char] = c; rx_char += 1; } else { rx_overrun += 1; } } } } } void __libc_init_array (void) __attribute__((weak)); void __libc_init_array () { }