From a1eff91d7703b8ee9e06e8bf60fbc27f22cd2aab Mon Sep 17 00:00:00 2001 From: jaseg Date: Fri, 8 Dec 2017 19:25:11 +0100 Subject: Basic UART working, but too slow --- fw/main.c | 351 ++++++++++---------------------------------------------------- 1 file changed, 54 insertions(+), 297 deletions(-) (limited to 'fw') diff --git a/fw/main.c b/fw/main.c index 1baf565..d40dbff 100644 --- a/fw/main.c +++ b/fw/main.c @@ -99,10 +99,10 @@ 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 enum { FB_WRITE, FB_UPDATE } fb_op = FB_WRITE; volatile union { - struct __attribute__((packed)) { struct framebuf fb; } set_fb_rq; - struct __attribute__((packed)) { uint8_t nbits; } set_nbits_rq; + struct __attribute__((packed)) { struct framebuf fb; uint8_t end[0]; } set_fb_rq; + struct __attribute__((packed)) { uint8_t nbits; uint8_t end[0]; } set_nbits_rq; uint8_t byte_data[0]; } rx_buf; @@ -278,246 +278,17 @@ enum Command { N_CMDS }; -enum ProtocolState { - PROT_ZERO_INVALID, - PROT_USART_ADDR_IDLE, - PROT_USART_ADDR_ERR, - PROT_USART_ADDR_COMPLETE, - PROT_USART_ADDR_CRC, - PROT_USART_ADDR_INIT, - PROT_USART_CMD, - PROT_DMA_INVALID=0x8, - PROT_DMA_CRC, - PROT_DMA_COMPLETE_USART, - PROT_DMA_COMPLETE_DMA, -}; - -volatile enum ProtocolState protocol_state = PROT_USART_ADDR_INIT; - -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; -static volatile size_t payload_len; - -bool dma_ch3_is_enabled(void) { - return DMA1_Channel3->CCR & DMA_CCR_EN; -} - -void kickoff_uart_rx_dma(volatile void *target, size_t len, enum ProtocolState state) { - /* This may be called from both DMA or USART ISRs. DMA channel 3 is disabled - * at this point. */ - if (dma_ch3_is_enabled()) - asm("bkpt"); - protocol_state = state; /* Finally, switch state */ - USART1->CR1 |= USART_CR1_IDLEIE; /* Enable USART IDLE interrupt */ - DMA1_Channel3->CMAR = (unsigned int)target; /* Set memory address */ - DMA1_Channel3->CNDTR = len; /* Set transfer count */ - USART1->CR1 &= ~USART_CR1_RXNEIE_Msk; /* Disable RX interrupt for duration of DMA transfer */ - DMA1->IFCR |= DMA_IFCR_CGIF3; /* Clear DMA channel 3 interrupt flag */ - DMA1_Channel3->CCR |= DMA_CCR_EN; /* Enable DMA transfer to write buffer */ - USART1->CR3 |= USART_CR3_DMAR; /* Enable USART-side of DMA channel 3 */ -} - -void disable_dma_ch3(void) { - /* May also be called with DMA ch3 already disabled */ - USART1->CR3 &= ~USART_CR3_DMAR_Msk; - DMA1_Channel3->CCR &= ~DMA_CCR_EN_Msk; - DMA1->IFCR |= DMA_IFCR_CGIF3; - /* This may be called from USART IRQ handler */ - NVIC_ClearPendingIRQ(DMA1_Channel2_3_IRQn); -} - -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; -} - -void kickoff_crc_dma(void) { - DMA1_Channel5->CNDTR = payload_len; - DMA1_Channel5->CCR |= DMA_CCR_EN; -} - -void disable_crc_dma(void) { - DMA1_Channel5->CCR &= ~DMA_CCR_EN_Msk; - DMA1->IFCR |= DMA_IFCR_CGIF5; -} - -void state_simple(enum ProtocolState state) { protocol_state = state; } -void state_usart_usart(enum ProtocolState state) { state_simple(state); } -void state_dma_dma(enum ProtocolState state) { state_simple(state); } - -void state_dma_usart(enum ProtocolState state) { - /* At this point the DMA channel has already been disabled. */ - if (DMA1_Channel3->CCR & DMA_CCR_EN) - asm("bkpt"); - USART1->RQR |= USART_RQR_RXFRQ; /* Clear receive flag FIXME necessary? */ - USART1->CR1 &= ~USART_CR1_IDLEIE_Msk; /* Disable IDLE interrupt */ - USART1->CR1 |= USART_CR1_RXNEIE; /* Enable receive interrupt */ - protocol_state = state; /* Finally, switch state */ -} - -void usart_mute(void) { - USART1->RQR |= USART_RQR_MMRQ; -} - -void usart_abort_dma(void) { - /* May also be called with DMA ch3 already disabled */ - disable_dma_ch3(); - state_dma_usart(PROT_USART_ADDR_IDLE); - usart_mute(); -} - -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 USART1_IRQHandler() { - int isr = USART1->ISR; - USART1->RQR |= USART_RQR_RXFRQ; - /* Overrun detected? */ - if (isr & USART_ISR_ORE) { - USART1->ICR |= USART_ICR_ORECF; /* Acknowledge overrun */ - asm("bkpt"); - goto errout; - } - - if (dma_ch3_is_enabled() && (isr & USART_ISR_IDLE)) { - USART1->ICR |= USART_ICR_IDLECF; /* Acknowledge idle condition */ - /* We may or may not be in DMA mode now */ - /* asm("bkpt"); FIXME debug when this should happen and when not and - * handle this appropriately */ - goto errout; - } - - if (!(isr & USART_ISR_RXNE)) - asm("bkpt"); - uint8_t data = USART1->RDR; - switch(protocol_state) { - case PROT_USART_ADDR_IDLE: - case PROT_USART_ADDR_ERR: - case PROT_USART_ADDR_COMPLETE: - case PROT_USART_ADDR_CRC: - case PROT_USART_ADDR_INIT: - if (data == bus_addr) { /* Are we addressed? */ - state_usart_usart(PROT_USART_CMD); - } else { /* We are not. Mute USART until next idle condition */ - asm("bkpt"); - usart_mute(); - goto errout; - } - break; - case PROT_USART_CMD: - if (data > N_CMDS) { - asm("bkpt"); - goto errout; - } - - rx_cmd = data; - crc_reset(); - crc_feed(data); - - size_t len = cmd_payload_len[data]; - payload_len = len; - if (len) { - /* Is rx_buf currently occupied by the main loop formatting frame data? */ - /* if (fb_op != FB_WRITE) FIXME DEBUG put this back - goto errout; - */ - kickoff_uart_rx_dma(&rx_buf, len, PROT_DMA_CRC); - } else { - kickoff_uart_rx_dma(&rx_crc, sizeof(rx_crc), PROT_DMA_COMPLETE_USART); - } - break; - default: - /* can/must not happen */ - asm("bkpt"); - } - - return; -errout: - /* We may or may not be in DMA mode now */ - usart_abort_dma(); -} - -void DMA1_Channel2_3_IRQHandler() { - /* DMA Transfer complete */ - disable_dma_ch3(); - - switch(protocol_state) { - case PROT_DMA_CRC: - kickoff_uart_rx_dma(&rx_crc, sizeof(rx_crc), PROT_DMA_COMPLETE_DMA); - state_dma_dma(PROT_DMA_COMPLETE_DMA); - kickoff_crc_dma(); - break; - case PROT_DMA_COMPLETE_USART: - case PROT_DMA_COMPLETE_DMA: - disable_crc_dma(); /* May or may not be enabled. Should long be done by now if enabled */ - - if (rx_crc != CRC->DR) { - crc_error_count++; - state_dma_usart(PROT_USART_ADDR_CRC); - break; - } - - 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)); /* Will turn itself off automatically */ - break; - default: - /* can/must not happen */ - asm("bkpt"); - } - - state_dma_usart(PROT_USART_ADDR_COMPLETE); - break; - default: - /* can/must not happen */ - asm("bkpt"); - } -} - -void DMA1_Channel4_5_IRQHandler() { - /* Handles only channel 4 (the transmit DMA channel). Channel 5 (receive - * CRC) is left free-running without interrupt service. - * - * Turn off this channel. */ - DMA1->IFCR |= DMA_IFCR_CGIF4; - DMA1_Channel4->CCR &= ~DMA_CCR_EN_Msk; -} +/* + 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; +*/ void uart_config(void) { USART1->CR1 = /* 8-bit -> M1, M0 clear */ @@ -529,59 +300,17 @@ void uart_config(void) { | USART_CR1_MME /* WAKE clear */ /* PCE, PS clear */ - | USART_CR1_RXNEIE + //| USART_CR1_RXNEIE /* other interrupts clear */ | USART_CR1_TE | USART_CR1_RE; //USART1->CR2 = USART_CR2_RTOEN; /* Timeout enable */ - USART1->CR3 = USART_CR3_DEM /* RS485 DE enable (output on RTS) */ - | USART_CR3_DMAT; + USART1->CR3 = USART_CR3_DEM; /* RS485 DE enable (output on RTS) */ + //| USART_CR3_DMAT; + /* Baud rate 2MBd */ int usartdiv = 25; USART1->BRR = usartdiv; USART1->CR1 |= USART_CR1_UE; - - /* Configure DMA 1 / Channel 3 for USART frame data reception: USART1->RDR -> rx_buf */ - DMA1_Channel3->CPAR = (unsigned int)&USART1->RDR; - DMA1_Channel3->CCR = (1<CCR |= - (0< CRC->DR */ - DMA1_Channel5->CPAR = (unsigned int)&CRC->DR; - DMA1_Channel5->CMAR = (unsigned int)&rx_buf; - DMA1_Channel5->CCR = (0<CCR |= - DMA_CCR_MEM2MEM /* Software trigger (precludes CIRC) */ - | DMA_CCR_DIR /* Read from memory */ - | (0<CPAR = (unsigned int)&USART1->TDR; - DMA1_Channel4->CMAR = (unsigned int)&tx_buf; - DMA1_Channel4->CCR = (0<CCR |= - DMA_CCR_DIR /* Read from memory */ - | (0<CFGR1 |= SYSCFG_CFGR1_USART1TX_DMA_RMP; - - NVIC_EnableIRQ(USART1_IRQn); - NVIC_SetPriority(USART1_IRQn, 2); - /* For channel 3 only */ - NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); - NVIC_SetPriority(DMA1_Channel2_3_IRQn, 2); - /* For channel 4 only */ - NVIC_EnableIRQ(DMA1_Channel4_5_IRQn); - NVIC_SetPriority(DMA1_Channel4_5_IRQn, 3); } #define ADC_OVERSAMPLING 12 @@ -695,15 +424,43 @@ int main(void) { cfg_timer3(); SysTick_Config(SystemCoreClock/1000); /* 1ms interval */ uart_config(); - adc_config(); + //adc_config(); + int rx_idx = 0; + int expect_framing = 1; + uint8_t data; + unsigned int num_overrun_errors = 0; + /* FIXME document framing/rx state machine */ while (42) { - if (fb_op == FB_FORMAT) { - transpose_data(rx_buf.byte_data, write_fb); - - fb_op = FB_UPDATE; - while (fb_op == FB_UPDATE) - ; + if (USART1->ISR & USART_ISR_ORE) { + USART1->ICR |= USART_ICR_ORECF; + num_overrun_errors ++; + } else if (USART1->ISR & USART_ISR_FE) { + USART1->ICR |= USART_ICR_FECF; + } else if (USART1->ISR & USART_ISR_RXNE) { + data = USART1->RDR; + /* + if (expect_framing) { + if (data == 0x42) { + expect_framing = 0; + } else { + rx_idx = 0; + } + } else { + rx_buf.byte_data[rx_idx] = data; + rx_idx++; + if (rx_idx >= sizeof(rx_buf.set_fb_rq)) { + rx_idx = 0; + if (fb_op == FB_WRITE) { + transpose_data(rx_buf.byte_data, write_fb); + fb_op = FB_UPDATE; + } + } + if ((rx_idx&0x1F) == 0) { + expect_framing = 1; + } + } + */ } } } @@ -729,6 +486,6 @@ void SysTick_Handler(void) { if (n++ == 1000) { n = 0; sys_time_seconds++; - } +} } -- cgit