diff options
author | jaseg <git@jaseg.net> | 2017-09-18 11:26:05 +0200 |
---|---|---|
committer | jaseg <git@jaseg.net> | 2017-09-18 11:30:25 +0200 |
commit | 723995c54131a132e8ab4bd8d9bbc1ca0eb1d3ee (patch) | |
tree | 813ce38adbd248b200c344bff5dbe622b45a78b1 /fw | |
parent | a823484163b7e52deb6a375fedea0a9454c138cc (diff) | |
download | 7seg-723995c54131a132e8ab4bd8d9bbc1ca0eb1d3ee.tar.gz 7seg-723995c54131a132e8ab4bd8d9bbc1ca0eb1d3ee.tar.bz2 7seg-723995c54131a132e8ab4bd8d9bbc1ca0eb1d3ee.zip |
hw v0.4
Diffstat (limited to 'fw')
-rw-r--r-- | fw/main.c | 272 |
1 files changed, 177 insertions, 95 deletions
@@ -10,6 +10,7 @@ #include <system_stm32f0xx.h> #include <stdint.h> +#include <stdbool.h> #include <string.h> #include <unistd.h> @@ -19,6 +20,44 @@ * Part number: STM32F030F4C6 */ +typedef struct +{ + volatile uint32_t CTRL; /*!< Offset: 0x000 (R/W) Control Register */ + volatile uint32_t CYCCNT; /*!< Offset: 0x004 (R/W) Cycle Count Register */ + volatile uint32_t CPICNT; /*!< Offset: 0x008 (R/W) CPI Count Register */ + volatile uint32_t EXCCNT; /*!< Offset: 0x00C (R/W) Exception Overhead Count Register */ + volatile uint32_t SLEEPCNT; /*!< Offset: 0x010 (R/W) Sleep Count Register */ + volatile uint32_t LSUCNT; /*!< Offset: 0x014 (R/W) LSU Count Register */ + volatile uint32_t FOLDCNT; /*!< Offset: 0x018 (R/W) Folded-instruction Count Register */ + volatile uint32_t PCSR; /*!< Offset: 0x01C (R/ ) Program Counter Sample Register */ + volatile uint32_t COMP0; /*!< Offset: 0x020 (R/W) Comparator Register 0 */ + volatile uint32_t MASK0; /*!< Offset: 0x024 (R/W) Mask Register 0 */ + volatile uint32_t FUNCTION0; /*!< Offset: 0x028 (R/W) Function Register 0 */ + uint32_t RESERVED0[1]; + volatile uint32_t COMP1; /*!< Offset: 0x030 (R/W) Comparator Register 1 */ + volatile uint32_t MASK1; /*!< Offset: 0x034 (R/W) Mask Register 1 */ + volatile uint32_t FUNCTION1; /*!< Offset: 0x038 (R/W) Function Register 1 */ + uint32_t RESERVED1[1]; +} DWT_Type; + +#define DWT ((DWT_Type *)0xE0001000) +DWT_Type *dwt = DWT; + +void dwt0_configure(volatile void *addr) { + dwt->COMP0 = (uint32_t)addr; + dwt->MASK0 = 0; +} + +enum DWT_Function { + DWT_R = 5, + DWT_W = 6, + DWT_RW = 7 +}; + +void dwt0_enable(enum DWT_Function function) { + dwt->FUNCTION0 = function; +} + /* Wait for about 0.2us */ static void tick(void) { /* 1 */ /* 2 */ /* 3 */ /* 4 */ /* 5 */ @@ -239,39 +278,60 @@ enum Command { N_CMDS }; -volatile enum { +enum ProtocolState { PROT_ZERO_INVALID, - PROT_ADDR_IDLE, - PROT_ADDR_ERR, - PROT_ADDR_COMPLETE, - PROT_ADDR_CRC, - PROT_ADDR_INIT, - PROT_CMD, - PROT_CRC, - PROT_COMPLETE, - PROT_INVALID, - N_PROT_STATES -} protocol_state = PROT_ADDR_INIT; + 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, +}; -void crc_reset(void) { - CRC->CR |= CRC_CR_RESET; - while (CRC->CR&CRC_CR_RESET) - ; +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 crc_feed(uint8_t data) { - *(uint8_t *)&CRC->DR = data; +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 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 */ +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; - DMA1_Channel3->CCR |= DMA_CCR_EN; - USART1->CR3 |= USART_CR3_DMAR; + /* This may be called from USART IRQ handler */ + NVIC_ClearPendingIRQ(DMA1_Channel2_3_IRQn); } void kickoff_uart_tx_dma(size_t len) { @@ -281,52 +341,87 @@ void kickoff_uart_tx_dma(size_t len) { 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, -}; +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; +} -int crc_error_count = 0; -static volatile uint32_t rx_crc; -static volatile enum Command rx_cmd; void USART1_IRQHandler() { - uint8_t data = USART1->RDR; int isr = USART1->ISR; USART1->RQR |= USART_RQR_RXFRQ; /* Overrun detected? */ if (isr & USART_ISR_ORE) { - USART1->ICR |= USART_ICR_ORECF; + USART1->ICR |= USART_ICR_ORECF; /* Acknowledge overrun */ asm("bkpt"); goto errout; } - if (isr & USART_ISR_IDLE) { - USART1->ICR |= USART_ICR_IDLECF; - USART1->CR3 &= ~USART_CR3_DMAR_Msk; - DMA1_Channel3->CCR &= ~DMA_CCR_EN_Msk; - DMA1->IFCR |= DMA_IFCR_CGIF3; - NVIC_ClearPendingIRQ(DMA1_Channel2_3_IRQn); - protocol_state = PROT_ADDR_IDLE; - USART1->RQR |= USART_RQR_RXFRQ; - USART1->CR1 |= USART_CR1_RXNEIE; - return; + + 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_ADDR_IDLE: - case PROT_ADDR_ERR: - case PROT_ADDR_COMPLETE: - case PROT_ADDR_CRC: - case PROT_ADDR_INIT: + 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? */ - protocol_state = PROT_CMD; + 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_CMD: + case PROT_USART_CMD: if (data > N_CMDS) { asm("bkpt"); goto errout; @@ -336,18 +431,16 @@ void USART1_IRQHandler() { crc_reset(); crc_feed(data); - size_t payload_len = cmd_payload_len[data]; - if (payload_len) { + 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; */ - DMA1_Channel5->CNDTR = payload_len; - protocol_state = PROT_CRC; - kickoff_uart_rx_dma(&rx_buf, payload_len); + kickoff_uart_rx_dma(&rx_buf, len, PROT_DMA_CRC); } else { - protocol_state = PROT_COMPLETE; - kickoff_uart_rx_dma(&rx_crc, sizeof(rx_crc)); + kickoff_uart_rx_dma(&rx_crc, sizeof(rx_crc), PROT_DMA_COMPLETE_USART); } break; default: @@ -357,44 +450,30 @@ void USART1_IRQHandler() { return; errout: - USART1->CR3 &= ~USART_CR3_DMAR_Msk; - DMA1_Channel3->CCR &= ~DMA_CCR_EN_Msk; - DMA1->IFCR |= DMA_IFCR_CGIF3; - protocol_state = PROT_ADDR_ERR; - USART1->RQR |= USART_RQR_MMRQ; - asm("bkpt"); + /* We may or may not be in DMA mode now */ + usart_abort_dma(); } void DMA1_Channel2_3_IRQHandler() { /* DMA Transfer complete */ - /* Disable this DMA channel */ - USART1->CR3 &= ~USART_CR3_DMAR_Msk; - DMA1_Channel3->CCR &= ~DMA_CCR_EN_Msk; - DMA1->IFCR |= DMA_IFCR_CGIF3; + disable_dma_ch3(); 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; + 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_COMPLETE: - DMA1_Channel5->CCR &= ~DMA_CCR_EN_Msk; - DMA1->IFCR |= DMA_IFCR_CGIF5; + 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++; - protocol_state = PROT_ADDR_CRC; - /* re-enable receive interrupt */ - USART1->RQR |= USART_RQR_RXFRQ; - USART1->RQR |= USART_RQR_MMRQ; - USART1->CR1 |= USART_CR1_RXNEIE; + state_dma_usart(PROT_USART_ADDR_CRC); break; } - protocol_state = PROT_ADDR_COMPLETE; - switch(rx_cmd) { case CMD_PING: tx_buf.ping_reply.magic = 0x39404142; @@ -416,16 +495,14 @@ void DMA1_Channel2_3_IRQHandler() { 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)); + kickoff_uart_tx_dma(sizeof(tx_buf.desc_reply)); /* Will turn itself off automatically */ break; default: /* can/must not happen */ asm("bkpt"); } - /* re-enable receive interrupt */ - USART1->RQR |= USART_RQR_RXFRQ; - USART1->CR1 |= USART_CR1_RXNEIE; + state_dma_usart(PROT_USART_ADDR_COMPLETE); break; default: /* can/must not happen */ @@ -434,6 +511,10 @@ void DMA1_Channel2_3_IRQHandler() { } 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; } @@ -449,7 +530,6 @@ void uart_config(void) { /* WAKE clear */ /* PCE, PS clear */ | USART_CR1_RXNEIE - | USART_CR1_IDLEIE /* other interrupts clear */ | USART_CR1_TE | USART_CR1_RE; @@ -495,11 +575,13 @@ void uart_config(void) { SYSCFG->CFGR1 |= SYSCFG_CFGR1_USART1TX_DMA_RMP; NVIC_EnableIRQ(USART1_IRQn); - NVIC_SetPriority(USART1_IRQn, 4); + NVIC_SetPriority(USART1_IRQn, 2); + /* For channel 3 only */ NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); - NVIC_SetPriority(DMA1_Channel2_3_IRQn, 3); + NVIC_SetPriority(DMA1_Channel2_3_IRQn, 2); + /* For channel 4 only */ NVIC_EnableIRQ(DMA1_Channel4_5_IRQn); - NVIC_SetPriority(DMA1_Channel4_5_IRQn, 5); + NVIC_SetPriority(DMA1_Channel4_5_IRQn, 3); } #define ADC_OVERSAMPLING 12 @@ -565,7 +647,7 @@ int main(void) { SystemCoreClockUpdate(); 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_APB2ENR_ADCEN; + RCC->APB2ENR |= RCC_APB2ENR_SPI1EN | RCC_APB2ENR_USART1EN | RCC_APB2ENR_SYSCFGEN | RCC_APB2ENR_ADCEN | RCC_APB2ENR_DBGMCUEN; RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; GPIOA->MODER |= |