From e6437f975b3e64dbd85d3939ae07893cf816a992 Mon Sep 17 00:00:00 2001 From: jaseg Date: Fri, 1 Sep 2017 20:26:05 +0200 Subject: UART magic seems to be working now --- fw/Makefile | 8 +- fw/main.c | 303 +++++++++++++++++++++++++++++++++++------------------- fw/stm32_flash.ld | 10 +- fw/transpose.h | 16 +-- 4 files changed, 216 insertions(+), 121 deletions(-) diff --git a/fw/Makefile b/fw/Makefile index b873ab5..f86df47 100644 --- a/fw/Makefile +++ b/fw/Makefile @@ -47,8 +47,14 @@ cmsis_exports.c: $(CMSIS_DEV_PATH)/Include/stm32f030x6.h $(CMSIS_PATH)/Include/c %.dot: %.elf r2 -a arm -qc 'aa;agC' $< 2>/dev/null >$@ + +sources.tar.xz: main.c transpose.c transpose.h + tar -caf $@ $^ + +sources.c: sources.tar.xz + xxd -i $< > $@ -main.elf: main.o startup_stm32f030x6.o system_stm32f0xx.o $(HAL_PATH)/Src/stm32f0xx_ll_utils.o base.o cmsis_exports.o transpose.o +main.elf: main.o startup_stm32f030x6.o system_stm32f0xx.o $(HAL_PATH)/Src/stm32f0xx_ll_utils.o base.o cmsis_exports.o transpose.o bus_addr.o $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) $(OBJCOPY) -O ihex $@ $(@:.elf=.hex) $(OBJCOPY) -O binary $@ $(@:.elf=.bin) diff --git a/fw/main.c b/fw/main.c index 5849566..db14e07 100644 --- a/fw/main.c +++ b/fw/main.c @@ -43,47 +43,41 @@ void strobe_leds(void) { GPIOA->BSRR = GPIO_BSRR_BR_9; } +#define FIRMWARE_VERSION 1 +#define HARDWARE_VERSION 1 + +volatile uint16_t adc_vcc_mv = 0; +volatile uint16_t adc_temp_tenth_celsius = 0; + volatile unsigned int sys_time = 0; +volatile unsigned int sys_time_seconds = 0; volatile struct framebuf fb[2] = {0}; volatile struct framebuf *read_fb=fb+0, *write_fb=fb+1; volatile int led_state = 0; volatile enum { FB_WRITE, FB_FORMAT, FB_UPDATE } fb_op; -volatile uint8_t rx_buf[sizeof(struct framebuf) + 4 /* crc */]; volatile union { - struct { + struct __attribute__((packed)) { struct framebuf fb; } set_fb_rq; + struct __attribute__((packed)) { uint8_t nbits; } set_nbits_rq; + uint8_t byte_data[0]; +} rx_buf; + +volatile union { + struct { uint32_t magic; } ping_reply; + struct __attribute__((packed)) { + uint8_t firmware_version, + hardware_version, + digit_rows, + digit_cols; + uint32_t uptime; uint32_t millifps; - } fps_reply; + uint16_t vcc_mv, + temp_tenth_celsius; + uint8_t nbits; + } desc_reply; } tx_buf; -volatile uint8_t this_addr = 0x05; /* FIXME */ - -union { - struct { - uint8_t device_id __attribute__((aligned(2))); - }; - uint16_t flash_data[0]; -} flash_data __attribute__((section ("configflash"))); - -void write_config(void *target, uint16_t value) { - FLASH->KEYR = 0x45670123; - FLASH->KEYR = 0xCDEF89AB; - FLASH->CR = FLASH_CR_PG; - *(uint16_t *)target = value; - while (FLASH->SR & FLASH_SR_BSY) - ; - FLASH->CR = FLASH_CR_LOCK; -} -void erase_config() { - FLASH->KEYR = 0x45670123; - FLASH->KEYR = 0xCDEF89AB; - FLASH->CR = FLASH_CR_PER; - FLASH->AR = (uint32_t)&flash_data; - FLASH->CR = FLASH_CR_STRT; - while (FLASH->SR & FLASH_SR_BSY) - ; - FLASH->CR = FLASH_CR_LOCK; -} +extern uint8_t bus_addr; #define LED_COMM 0x0001 #define LED_ERROR 0x0002 @@ -157,6 +151,7 @@ void SPI1_IRQHandler() { uint8_t segment_map[8] = {5, 7, 6, 4, 1, 3, 0, 2}; static volatile int frame_duration_us; +volatile int nbits = MAX_BITS; /* returns new bit time in cycles */ int shift_data() { static int active_segment = 0; @@ -165,11 +160,11 @@ int shift_data() { /* Note: On boot, multiplexing will start with bit 1 due to the next few lines. This is perfectly ok. */ active_bit++; - if (active_bit == nbits) { + if (active_bit >= nbits) { active_bit = 0; active_segment++; - if (active_segment == nsegments) { + if (active_segment == NSEGMENTS) { active_segment = 0; int time = stk_microseconds(); @@ -183,13 +178,13 @@ int shift_data() { } } - spi_word = read_fb->data[active_bit*frame_size_words + active_segment]; + spi_word = read_fb->data[active_bit*FRAME_SIZE_WORDS + active_segment]; spi_state = SPI_AUX; SPI1->DR = (read_fb->brightness ? SR_ILED_HIGH : SR_ILED_LOW) | (led_state<<1) | (0xff00 ^ (0x100<data[active_bit*frame_size_words + active_segment]; + spi_word = read_fb->data[active_bit*FRAME_SIZE_WORDS + active_segment]; spi_state = SPI_WORD0; SPI1->DR = spi_word>>16; } @@ -233,81 +228,184 @@ void TIM3_IRQHandler() { enum Command { CMD_PING, - CMD_SET_ADDR, CMD_SET_FB, + CMD_SET_NBITS, CMD_GET_DESC, - CMD_GET_FRAMERATE, - CMD_ERASE_CONFIG, + N_CMDS }; enum { PROT_ADDR, PROT_CMD, - PROT_ + PROT_CRC, + PROT_COMPLETE, + PROT_INVALID, + N_PROT_STATES } protocol_state = PROT_ADDR; -int gaddr; +void crc_reset(void) { + CRC->CR |= CRC_CR_RESET; + while (CRC->CR&CRC_CR_RESET) + ; +} + +void crc_feed(uint8_t data) { + *(uint8_t *)&CRC->DR = data; +} + +void kickoff_uart_rx_dma(volatile void *target, size_t len) { + DMA1_Channel3->CMAR = (unsigned int)target; + DMA1_Channel3->CNDTR = len; + /* Disable RX interrupt for duration of DMA transfer */ + USART1->CR1 &= ~USART_CR1_RXNEIE_Msk; + /* Enable DMA transfer to write buffer */ + DMA1->IFCR |= DMA_IFCR_CGIF3; + DMA1_Channel3->CCR |= DMA_CCR_EN; + USART1->CR3 |= USART_CR3_DMAR; +} + +void kickoff_uart_tx_dma(size_t len) { + DMA1_Channel4->CNDTR = len; + USART1->ICR |= USART_ICR_TCCF; /* FIXME: (1) is this necessary? (2) where should this be done? */ + DMA1_Channel4->CCR |= DMA_CCR_EN; + USART1->RQR |= USART_RQR_MMRQ; +} + +static size_t cmd_payload_len[N_CMDS] = { + [CMD_PING] = 0, + [CMD_SET_FB] = sizeof(rx_buf.set_fb_rq), + [CMD_SET_NBITS] = sizeof(rx_buf.set_nbits_rq), + [CMD_GET_DESC] = 0, +}; + +int crc_error_count = 0; +static volatile uint32_t rx_crc; +static volatile enum Command rx_cmd; void USART1_IRQHandler() { - gaddr = USART1->RDR; + + uint8_t data = USART1->RDR; + int isr = USART1->ISR; USART1->RQR |= USART_RQR_RXFRQ; - int addr = gaddr; /* FIXME DEBUG */ - int cmd = addr>>5; - addr &= 0x1F; /* Overrun detected? */ - if (USART1->ISR & USART_ISR_ORE) { + if (isr & USART_ISR_ORE) { USART1->ICR |= USART_ICR_ORECF; - USART1->RQR |= USART_RQR_MMRQ; + goto errout; } - /* Are we addressed? */ - if (addr != this_addr) { - asm("bkpt"); - /* We are not. Mute USART until next idle condition */ - USART1->RQR |= USART_RQR_MMRQ; - } else { - /* We are. Switch by command. */ - switch (cmd) { - case CMD_PING: - USART1->TDR = 42; - USART1->RQR |= USART_RQR_MMRQ; - break; - case CMD_SET_FB: - /* Are we ready to process new frame data? */ - if (fb_op != FB_WRITE) { - //asm("bkpt"); /* FIXME DEBUG */ - goto errout; /* Error: Not yet ready to receive new packet */ - } - /* Disable this RX interrupt for duration of DMA transfer */ - USART1->CR1 &= ~USART_CR1_RXNEIE_Msk; - /* Enable DMA transfer to write buffer */ - DMA1->IFCR |= DMA_IFCR_CGIF3; - DMA1_Channel3->CCR |= DMA_CCR_EN; - USART1->CR3 |= USART_CR3_DMAR; - break; - case CMD_GET_FRAMERATE: - tx_buf.fps_reply.millifps = frame_duration_us > 0 ? 1000000000 / frame_duration_us : 0; - DMA1_Channel4->CNDTR = sizeof(tx_buf.fps_reply); - USART1->ICR |= USART_ICR_TCCF; /* FIXME: (1) is this necessary? (2) where should this be done? */ - DMA1_Channel4->CCR |= DMA_CCR_EN; - USART1->RQR |= USART_RQR_MMRQ; - break; + if (isr & USART_ISR_IDLE) { + USART1->ICR |= USART_ICR_IDLECF; + USART1->CR3 &= ~USART_CR3_DMAR_Msk; + DMA1_Channel3->CCR &= ~DMA_CCR_EN_Msk; + protocol_state = PROT_ADDR; + USART1->RQR |= USART_RQR_RXFRQ; + USART1->CR1 |= USART_CR1_RXNEIE; + return; + } + + switch(protocol_state) { + case PROT_ADDR: + if (data == bus_addr) /* Are we addressed? */ + protocol_state = PROT_CMD; + else /* We are not. Mute USART until next idle condition */ + goto errout; + break; + case PROT_CMD: + if (data > N_CMDS) + goto errout; + + rx_cmd = data; + crc_reset(); + crc_feed(data); + + size_t payload_len = cmd_payload_len[data]; + if (payload_len) { + /* Is rx_buf currently occupied by the main loop formatting frame data? */ + if (fb_op != FB_WRITE) + goto errout; + kickoff_uart_rx_dma(&rx_buf, payload_len); + DMA1_Channel5->CNDTR = payload_len; + protocol_state = PROT_CRC; + } else { + kickoff_uart_rx_dma(&rx_crc, sizeof(rx_crc)); + protocol_state = PROT_COMPLETE; } + break; + default: + /* can/must not happen */ + asm("bkpt"); } + + return; errout: - /* FIXME */ -return; + protocol_state = PROT_ADDR; + USART1->RQR |= USART_RQR_MMRQ; } void DMA1_Channel2_3_IRQHandler() { /* DMA Transfer complete */ - /* ...and disable this DMA channel */ + /* Disable this DMA channel */ USART1->CR3 &= ~USART_CR3_DMAR_Msk; DMA1_Channel3->CCR &= ~DMA_CCR_EN_Msk; - /* Kick off formatting code in main loop outside interrupt context */ - fb_op = FB_FORMAT; DMA1->IFCR |= DMA_IFCR_CGIF3; - /* re-enable receive interrupt */ - USART1->RQR |= USART_RQR_RXFRQ; - USART1->CR1 |= USART_CR1_RXNEIE; + + switch(protocol_state) { + case PROT_CRC: + kickoff_uart_rx_dma(&rx_crc, sizeof(rx_crc)); + protocol_state = PROT_COMPLETE; + + DMA1_Channel5->CCR |= DMA_CCR_EN; + break; + case PROT_COMPLETE: + DMA1_Channel5->CCR &= ~DMA_CCR_EN_Msk; + DMA1->IFCR |= DMA_IFCR_CGIF5; + + if (rx_crc != CRC->DR) { + crc_error_count++; + protocol_state = PROT_ADDR; + /* re-enable receive interrupt */ + USART1->RQR |= USART_RQR_RXFRQ; + USART1->RQR |= USART_RQR_MMRQ; + USART1->CR1 |= USART_CR1_RXNEIE; + break; + } + + protocol_state = PROT_ADDR; + + switch(rx_cmd) { + case CMD_PING: + tx_buf.ping_reply.magic = 0x39404142; + kickoff_uart_tx_dma(sizeof(tx_buf.ping_reply)); + break;; + case CMD_SET_FB: + fb_op = FB_UPDATE; + break; + case CMD_SET_NBITS: + nbits = rx_buf.set_nbits_rq.nbits; + break; + case CMD_GET_DESC: + tx_buf.desc_reply.firmware_version = FIRMWARE_VERSION; + tx_buf.desc_reply.hardware_version = HARDWARE_VERSION; + tx_buf.desc_reply.digit_rows = NROWS; + tx_buf.desc_reply.digit_cols = NCOLS; + tx_buf.desc_reply.uptime = sys_time_seconds; + tx_buf.desc_reply.vcc_mv = adc_vcc_mv; + tx_buf.desc_reply.temp_tenth_celsius = adc_temp_tenth_celsius; + tx_buf.desc_reply.nbits = nbits; + tx_buf.desc_reply.millifps = frame_duration_us > 0 ? 1000000000 / frame_duration_us : 0; + kickoff_uart_tx_dma(sizeof(tx_buf.desc_reply)); + break; + default: + /* can/must not happen */ + asm("bkpt"); + } + + /* re-enable receive interrupt */ + USART1->RQR |= USART_RQR_RXFRQ; + USART1->CR1 |= USART_CR1_RXNEIE; + break; + default: + /* can/must not happen */ + asm("bkpt"); + } } void DMA1_Channel4_5_IRQHandler() { @@ -326,6 +424,7 @@ void uart_config(void) { /* WAKE clear */ /* PCE, PS clear */ | USART_CR1_RXNEIE + | USART_CR1_IDLEIE /* other interrupts clear */ | USART_CR1_TE | USART_CR1_RE; @@ -338,8 +437,6 @@ void uart_config(void) { /* Configure DMA 1 / Channel 3 for USART frame data reception: USART1->RDR -> rx_buf */ DMA1_Channel3->CPAR = (unsigned int)&USART1->RDR; - DMA1_Channel3->CMAR = (unsigned int)rx_buf; - DMA1_Channel3->CNDTR = sizeof(rx_buf); DMA1_Channel3->CCR = (1<CCR |= (0< CRC->DR */ DMA1_Channel5->CPAR = (unsigned int)&CRC->DR; - DMA1_Channel5->CMAR = (unsigned int)rx_buf; + DMA1_Channel5->CMAR = (unsigned int)&rx_buf; DMA1_Channel5->CCR = (0<CCR |= DMA_CCR_MEM2MEM /* Software trigger (precludes CIRC) */ @@ -380,7 +477,6 @@ void uart_config(void) { NVIC_SetPriority(DMA1_Channel4_5_IRQn, 5); } -int errcnt = 0; int main(void) { RCC->CR |= RCC_CR_HSEON; while (!(RCC->CR&RCC_CR_HSERDY)); @@ -393,7 +489,7 @@ int main(void) { RCC->CFGR |= (2<AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_DMAEN | RCC_AHBENR_CRCEN; + RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_DMAEN | RCC_AHBENR_CRCEN | RCC_AHBENR_FLITFEN; RCC->APB2ENR |= RCC_APB2ENR_SPI1EN | RCC_APB2ENR_USART1EN | RCC_APB2ENR_SYSCFGEN; RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; @@ -445,25 +541,11 @@ int main(void) { while (42) { if (fb_op == FB_FORMAT) { - CRC->CR |= CRC_CR_RESET; - DMA1_Channel5->CNDTR = sizeof(struct framebuf); - DMA1_Channel5->CCR |= DMA_CCR_EN; + transpose_data(rx_buf.byte_data, write_fb); - transpose_data(rx_buf, write_fb); - - while (!(DMA1->ISR & DMA_ISR_TCIF4)) + fb_op = FB_UPDATE; + while (fb_op == FB_UPDATE) ; - DMA1->IFCR |= DMA_IFCR_CGIF4; - DMA1_Channel5->CCR &= ~DMA_CCR_EN_Msk; - - if (CRC->DR != *(uint32_t *)(rx_buf+sizeof(struct framebuf))) { - fb_op = FB_WRITE; - errcnt++; - } else { - fb_op = FB_UPDATE; - while (fb_op == FB_UPDATE) - ; - } } } } @@ -484,6 +566,11 @@ void PendSV_Handler(void) { } void SysTick_Handler(void) { + static int n = 0; sys_time++; + if (n++ == 1000) { + n = 0; + sys_time_seconds++; + } } diff --git a/fw/stm32_flash.ld b/fw/stm32_flash.ld index 5d22b48..b763d8f 100644 --- a/fw/stm32_flash.ld +++ b/fw/stm32_flash.ld @@ -2,8 +2,8 @@ ENTRY(Reset_Handler) MEMORY { - FLASH (rx): ORIGIN = 0x08000000, LENGTH = 14K - CONFIGFLASH (rw): ORIGIN = 0x08003800, LENGTH = 2K + FLASH (rx): ORIGIN = 0x08000000, LENGTH = 0x3C00 + CONFIGFLASH (rw): ORIGIN = 0x08003C00, LENGTH = 0x400 RAM (xrw): ORIGIN = 0x20000000, LENGTH = 4K } @@ -39,11 +39,13 @@ SECTIONS { _sidata = _etext; } >FLASH + /* .configflash : { - . = ALIGN(2048); + . = ALIGN(0x400); *(.configdata) _econfig = .; - } >CONFIGFLASH + } >FLASH + */ /* This is the initialized data section The program executes knowing that the data is in the RAM diff --git a/fw/transpose.h b/fw/transpose.h index 1927a72..b1ca41b 100644 --- a/fw/transpose.h +++ b/fw/transpose.h @@ -3,25 +3,25 @@ #include -enum Segment { SegA, SegB, SegC, SegD, SegE, SegF, SegG, SegDP, nsegments }; +enum Segment { SegA, SegB, SegC, SegD, SegE, SegF, SegG, SegDP, NSEGMENTS }; enum { - nrows = 4, - ncols = 8, - nbits = 10, + NROWS = 4, + NCOLS = 8, + MAX_BITS = 10, }; enum { - frame_size_words = nrows*ncols*nsegments/32, + FRAME_SIZE_WORDS = NROWS*NCOLS*NSEGMENTS/32, }; struct framebuf { /* Multiplexing order: first Digits, then Time/bits, last Segments */ union { - uint32_t data[nbits*frame_size_words]; + uint32_t data[MAX_BITS*FRAME_SIZE_WORDS]; struct { struct { - uint32_t data[frame_size_words]; - } frame[nbits]; + uint32_t data[FRAME_SIZE_WORDS]; + } frame[MAX_BITS]; }; }; uint8_t brightness; /* 0 or 1; controls global brighntess control */ -- cgit