diff --git a/lib-dmx/src/gd32/dmx.cpp b/lib-dmx/src/gd32/dmx.cpp index a5ab3f3..9c29807 100644 --- a/lib-dmx/src/gd32/dmx.cpp +++ b/lib-dmx/src/gd32/dmx.cpp @@ -72,7 +72,7 @@ void console_error(const char *); /** * https://www.gd32-dmx.org/memory.html */ -#if defined (GD32F20X) ||defined (GD32F4XX) +#if defined (GD32F20X) || defined (GD32F4XX) # define SECTION_DMA_BUFFER __attribute__ ((section (".dmx"))) #else # define SECTION_DMA_BUFFER @@ -181,7 +181,11 @@ static void irq_handler_dmx_rdm_input(const uint32_t uart, const uint32_t nPortI if (RESET != (USART_REG_VAL(uart, USART_FLAG_FERR) & BIT(USART_BIT_POS(USART_FLAG_FERR)))) { USART_REG_VAL(uart, USART_FLAG_FERR) &= ~BIT(USART_BIT_POS(USART_FLAG_FERR)); +#if defined (GD32H7XX) + static_cast(GET_BITS(USART_RDATA(uart), 0U, 8U)); +#else static_cast(GET_BITS(USART_DATA(uart), 0U, 8U)); +#endif if (s_RxBuffer[nPortIndex].State == TxRxState::IDLE) { s_RxBuffer[nPortIndex].Dmx.nSlotsInPacket = 0; s_RxBuffer[nPortIndex].State = TxRxState::BREAK; @@ -189,7 +193,11 @@ static void irq_handler_dmx_rdm_input(const uint32_t uart, const uint32_t nPortI return; } +#if defined (GD32H7XX) + const auto data = static_cast(GET_BITS(USART_RDATA(uart), 0U, 8U)); +#else const auto data = static_cast(GET_BITS(USART_DATA(uart), 0U, 8U)); +#endif switch (s_RxBuffer[nPortIndex].State) { case TxRxState::IDLE: @@ -637,23 +645,34 @@ static void usart_dma_config(void) { DMA_PARAMETER_STRUCT dma_init_struct; rcu_periph_clock_enable(RCU_DMA0); rcu_periph_clock_enable(RCU_DMA1); +#if defined (GD32H7XX) + rcu_periph_clock_enable(RCU_DMAMUX); +#endif /* * USART 0 */ #if defined (DMX_USE_USART0) dma_deinit(USART0_DMA, USART0_TX_DMA_CH); +# if defined (GD32H7XX) + dma_init_struct.request = DMA_REQUEST_USART0_TX; +# endif dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL; dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; -#if !defined (GD32F4XX) +# if defined (GD32F4XX) || defined (GD32H7XX) +# else dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT; -#endif +# endif +# if defined (GD32H7XX) + dma_init_struct.periph_addr = (uint32_t) &USART_TDATA(USART0); +# else dma_init_struct.periph_addr = USART0 + 0x04U; +# endif dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; -#if !defined (GD32F4XX) - dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; -#else +# if defined (GD32F4XX) || defined (GD32H7XX) dma_init_struct.periph_memory_width = DMA_PERIPHERAL_WIDTH_8BIT; -#endif +# else + dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; +# endif dma_init_struct.priority = DMA_PRIORITY_HIGH; dma_init(USART0_DMA, USART0_TX_DMA_CH, &dma_init_struct); /* configure DMA mode */ @@ -676,18 +695,26 @@ static void usart_dma_config(void) { */ #if defined (DMX_USE_USART1) dma_deinit(USART1_DMA, USART1_TX_DMA_CH); +# if defined (GD32H7XX) + dma_init_struct.request = DMA_REQUEST_USART1_TX; +# endif dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL; dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; -#if !defined (GD32F4XX) +# if defined (GD32F4XX) || defined (GD32H7XX) +# else dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT; -#endif +# endif +# if defined (GD32H7XX) + dma_init_struct.periph_addr = (uint32_t) &USART_TDATA(USART1); +# else dma_init_struct.periph_addr = USART1 + 0x04U; +# endif dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; -#if !defined (GD32F4XX) - dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; -#else +# if defined (GD32F4XX) || defined (GD32H7XX) dma_init_struct.periph_memory_width = DMA_PERIPHERAL_WIDTH_8BIT; -#endif +# else + dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; +# endif dma_init_struct.priority = DMA_PRIORITY_HIGH; dma_init(USART1_DMA, USART1_TX_DMA_CH, &dma_init_struct); /* configure DMA mode */ @@ -705,17 +732,25 @@ static void usart_dma_config(void) { */ #if defined (DMX_USE_USART2) dma_deinit(USART2_DMA, USART2_TX_DMA_CH); +# if defined (GD32H7XX) + dma_init_struct.request = DMA_REQUEST_USART2_TX; +# endif dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL; dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; -# if !defined (GD32F4XX) +# if defined (GD32F4XX) || defined (GD32H7XX) +# else dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT; # endif +# if defined (GD32H7XX) + dma_init_struct.periph_addr = (uint32_t) &USART_TDATA(USART2); +# else dma_init_struct.periph_addr = USART2 + 0x04U; +# endif dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; -# if !defined (GD32F4XX) - dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; -# else +# if defined (GD32F4XX) || defined (GD32H7XX) dma_init_struct.periph_memory_width = DMA_PERIPHERAL_WIDTH_8BIT; +# else + dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; # endif dma_init_struct.priority = DMA_PRIORITY_HIGH; dma_init(USART2_DMA, USART2_TX_DMA_CH, &dma_init_struct); @@ -726,12 +761,12 @@ static void usart_dma_config(void) { dma_channel_subperipheral_select(USART2_DMA, USART2_TX_DMA_CH, USART2_TX_DMA_SUBPERIx); # endif dma_interrupt_disable(USART2_DMA, USART2_TX_DMA_CH, DMA_INTERRUPT_DISABLE); -# if !defined (GD32F4XX) - NVIC_SetPriority(DMA0_Channel1_IRQn, 1); - NVIC_EnableIRQ(DMA0_Channel1_IRQn); -# else +#if defined (GD32F4XX) || defined (GD32H7XX) NVIC_SetPriority(DMA0_Channel3_IRQn, 1); NVIC_EnableIRQ(DMA0_Channel3_IRQn); +# else + NVIC_SetPriority(DMA0_Channel1_IRQn, 1); + NVIC_EnableIRQ(DMA0_Channel1_IRQn); # endif #endif /* @@ -739,18 +774,26 @@ static void usart_dma_config(void) { */ #if defined (DMX_USE_UART3) dma_deinit(UART3_DMA, UART3_TX_DMA_CH); +# if defined (GD32H7XX) + dma_init_struct.request = DMA_REQUEST_UART3_TX; +# endif dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL; dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; -#if !defined (GD32F4XX) +# if defined (GD32F4XX) || defined (GD32H7XX) +# else dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT; -#endif +# endif +# if defined (GD32H7XX) + dma_init_struct.periph_addr = (uint32_t) &USART_TDATA(UART3); +# else dma_init_struct.periph_addr = UART3 + 0x04U; +# endif dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; -#if !defined (GD32F4XX) - dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; -#else +# if defined (GD32F4XX) || defined (GD32H7XX) dma_init_struct.periph_memory_width = DMA_PERIPHERAL_WIDTH_8BIT; -#endif +# else + dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; +# endif dma_init_struct.priority = DMA_PRIORITY_HIGH; dma_init(UART3_DMA, UART3_TX_DMA_CH, &dma_init_struct); /* configure DMA mode */ @@ -773,17 +816,25 @@ static void usart_dma_config(void) { */ #if defined (DMX_USE_UART4) dma_deinit(UART4_DMA, UART4_TX_DMA_CH); +# if defined (GD32H7XX) + dma_init_struct.request = DMA_REQUEST_UART4_TX; +# endif dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL; dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; -#if !defined (GD32F4XX) +# if defined (GD32F4XX) || defined (GD32H7XX) +# else dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT; -#endif +# endif +# if defined (GD32H7XX) + dma_init_struct.periph_addr = (uint32_t) &USART_TDATA(UART4); +# else dma_init_struct.periph_addr = UART4 + 0x04U; +# endif dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; -#if !defined (GD32F4XX) - dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; -#else +#if defined (GD32F4XX) || defined (GD32H7XX) dma_init_struct.periph_memory_width = DMA_PERIPHERAL_WIDTH_8BIT; +#else + dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; #endif dma_init_struct.priority = DMA_PRIORITY_HIGH; dma_init(UART4_DMA, UART4_TX_DMA_CH, &dma_init_struct); @@ -807,16 +858,23 @@ static void usart_dma_config(void) { */ #if defined (DMX_USE_USART5) dma_deinit(USART5_DMA, USART5_TX_DMA_CH); +# if defined (GD32H7XX) + dma_init_struct.request = DMA_REQUEST_USART5_TX; +# endif dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL; dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; -#if !defined (GD32F4XX) +# if defined (GD32F20X) dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT; -#endif +# endif +# if defined (GD32H7XX) + dma_init_struct.periph_addr = (uint32_t) &USART_TDATA(USART5); +# else dma_init_struct.periph_addr = USART5 + 0x04U; +# endif dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; -#if !defined (GD32F4XX) +#if defined (GD32F20X) dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; -#else +# else dma_init_struct.periph_memory_width = DMA_PERIPHERAL_WIDTH_8BIT; #endif dma_init_struct.priority = DMA_PRIORITY_HIGH; @@ -836,18 +894,25 @@ static void usart_dma_config(void) { */ #if defined (DMX_USE_UART6) dma_deinit(UART6_DMA, UART6_TX_DMA_CH); +# if defined (GD32H7XX) + dma_init_struct.request = DMA_REQUEST_UART6_TX; +# endif dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL; dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; -#if !defined (GD32F4XX) +# if defined (GD32F20X) dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT; -#endif +# endif +# if defined (GD32H7XX) + dma_init_struct.periph_addr = (uint32_t) &USART_TDATA(UART6); +# else dma_init_struct.periph_addr = UART6 + 0x04U; +# endif dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; -#if !defined (GD32F4XX) +# if defined (GD32F20X) dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; -#else +# else dma_init_struct.periph_memory_width = DMA_PERIPHERAL_WIDTH_8BIT; -#endif +# endif dma_init_struct.priority = DMA_PRIORITY_HIGH; dma_init(UART6_DMA, UART6_TX_DMA_CH, &dma_init_struct); /* configure DMA mode */ @@ -870,18 +935,25 @@ static void usart_dma_config(void) { */ #if defined (DMX_USE_UART7) dma_deinit(UART7_DMA, UART7_TX_DMA_CH); +# if defined (GD32H7XX) + dma_init_struct.request = DMA_REQUEST_UART7_TX; +# endif dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL; dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; -#if !defined (GD32F4XX) +# if defined (GD32F20X) dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT; -#endif +# endif +# if defined (GD32H7XX) + dma_init_struct.periph_addr = (uint32_t) &USART_TDATA(UART7); +# else dma_init_struct.periph_addr = UART7 + 0x04U; +# endif dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; -#if !defined (GD32F4XX) +# if defined (GD32F20X) dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; -#else +# else dma_init_struct.periph_memory_width = DMA_PERIPHERAL_WIDTH_8BIT; -#endif +# endif dma_init_struct.priority = DMA_PRIORITY_HIGH; dma_init(UART7_DMA, UART7_TX_DMA_CH, &dma_init_struct); /* configure DMA mode */ @@ -890,7 +962,7 @@ static void usart_dma_config(void) { # if defined (GD32F4XX) dma_channel_subperipheral_select(UART7_DMA, UART7_TX_DMA_CH, UART7_TX_DMA_SUBPERIx); # endif -# if !defined (GD32F4XX) +#if defined (GD32F20X) NVIC_SetPriority(DMA1_Channel3_IRQn, 1); NVIC_EnableIRQ(DMA1_Channel3_IRQn); # else @@ -990,12 +1062,12 @@ void TIMER1_IRQHandler() { _gpio_mode_output(USART2_GPIO_PORT, USART2_TX_PIN); GPIO_BC(USART2_GPIO_PORT) = USART2_TX_PIN; s_TxBuffer[dmx::config::USART2_PORT].State = TxRxState::BREAK; - timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_2, TIMER_CNT(TIMER1) + s_nDmxTransmitBreakTime); + TIMER_CH2CV(TIMER1) = TIMER_CNT(TIMER1) + s_nDmxTransmitBreakTime; break; case TxRxState::BREAK: _gpio_mode_af(USART2_GPIO_PORT, USART2_TX_PIN, USART2); s_TxBuffer[dmx::config::USART2_PORT].State = TxRxState::MAB; - timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_2, TIMER_CNT(TIMER1) + s_nDmxTransmitMabTime); + TIMER_CH2CV(TIMER1) = TIMER_CNT(TIMER1) + s_nDmxTransmitMabTime; break; case TxRxState::MAB: { uint32_t dmaCHCTL = DMA_CHCTL(USART2_DMA, USART2_TX_DMA_CH); @@ -1109,12 +1181,12 @@ void TIMER4_IRQHandler() { _gpio_mode_output(USART5_GPIO_PORT, USART5_TX_PIN); GPIO_BC(USART5_GPIO_PORT) = USART5_TX_PIN; s_TxBuffer[dmx::config::USART5_PORT].State = TxRxState::BREAK; - timer_channel_output_pulse_value_config(TIMER4, TIMER_CH_1, TIMER_CNT(TIMER4) + s_nDmxTransmitBreakTime); + TIMER_CH1CV(TIMER4) = TIMER_CNT(TIMER4) + s_nDmxTransmitBreakTime; break; case TxRxState::BREAK: _gpio_mode_af(USART5_GPIO_PORT, USART5_TX_PIN, USART5); s_TxBuffer[dmx::config::USART5_PORT].State = TxRxState::MAB; - timer_channel_output_pulse_value_config(TIMER4, TIMER_CH_1, TIMER_CNT(TIMER4) + s_nDmxTransmitMabTime); + TIMER_CH1CV(TIMER4) = TIMER_CNT(TIMER4) + s_nDmxTransmitMabTime; break; case TxRxState::MAB: { uint32_t dmaCHCTL = DMA_CHCTL(USART5_DMA, USART5_TX_DMA_CH); @@ -1215,6 +1287,7 @@ void TIMER4_IRQHandler() { return; } #endif + timer_interrupt_flag_clear(TIMER4, ~0); } #if !defined(CONFIG_DMX_TRANSMIT_ONLY) @@ -1336,10 +1409,10 @@ extern "C" { * USART 0 */ #if defined (DMX_USE_USART0) -# if !defined (GD32F4XX) -void DMA0_Channel3_IRQHandler() { - if (dma_interrupt_flag_get(DMA0, DMA_CH3, DMA_INTERRUPT_FLAG_GET) == SET) { - dma_interrupt_disable(DMA0, DMA_CH3, DMA_INTERRUPT_DISABLE); +# if defined (GD32F4XX) || defined (GD32H7XX) +void DMA1_Channel7_IRQHandler() { + if (dma_interrupt_flag_get(DMA1, DMA_CH7, DMA_INTERRUPT_FLAG_GET) == SET) { + dma_interrupt_disable(DMA1, DMA_CH7, DMA_INTERRUPT_DISABLE); if (s_TxBuffer[dmx::config::USART0_PORT].outputStyle == dmx::OutputStyle::DELTA) { s_TxBuffer[dmx::config::USART0_PORT].State = TxRxState::IDLE; @@ -1349,12 +1422,12 @@ void DMA0_Channel3_IRQHandler() { } } - dma_interrupt_flag_clear(DMA0, DMA_CH3, DMA_INTERRUPT_FLAG_CLEAR); + dma_interrupt_flag_clear(DMA1, DMA_CH7, DMA_INTERRUPT_FLAG_CLEAR); } # else -void DMA1_Channel7_IRQHandler() { - if (dma_interrupt_flag_get(DMA1, DMA_CH7, DMA_INTERRUPT_FLAG_GET) == SET) { - dma_interrupt_disable(DMA1, DMA_CH7, DMA_INTERRUPT_DISABLE); +void DMA0_Channel3_IRQHandler() { + if (dma_interrupt_flag_get(DMA0, DMA_CH3, DMA_INTERRUPT_FLAG_GET) == SET) { + dma_interrupt_disable(DMA0, DMA_CH3, DMA_INTERRUPT_DISABLE); if (s_TxBuffer[dmx::config::USART0_PORT].outputStyle == dmx::OutputStyle::DELTA) { s_TxBuffer[dmx::config::USART0_PORT].State = TxRxState::IDLE; @@ -1364,7 +1437,7 @@ void DMA1_Channel7_IRQHandler() { } } - dma_interrupt_flag_clear(DMA1, DMA_CH7, DMA_INTERRUPT_FLAG_CLEAR); + dma_interrupt_flag_clear(DMA0, DMA_CH3, DMA_INTERRUPT_FLAG_CLEAR); } # endif #endif @@ -1391,12 +1464,10 @@ void DMA0_Channel6_IRQHandler() { * USART 2 */ #if defined (DMX_USE_USART2) -# if !defined (GD32F4XX) -void DMA0_Channel1_IRQHandler() { - if (dma_interrupt_flag_get(DMA0, DMA_CH1, DMA_INTERRUPT_FLAG_GET) == SET) { - dma_interrupt_disable(DMA0, DMA_CH1, DMA_INTERRUPT_DISABLE); - - usart_flag_clear(USART2, USART_FLAG_TC); +# if defined (GD32F4XX) || defined (GD32H7XX) +void DMA0_Channel3_IRQHandler() { + if (dma_interrupt_flag_get(DMA0, DMA_CH3, DMA_INTERRUPT_FLAG_GET) == SET) { + dma_interrupt_disable(DMA0, DMA_CH3, DMA_INTERRUPT_DISABLE); if (s_TxBuffer[dmx::config::USART2_PORT].outputStyle == dmx::OutputStyle::DELTA) { s_TxBuffer[dmx::config::USART2_PORT].State = TxRxState::IDLE; @@ -1406,12 +1477,14 @@ void DMA0_Channel1_IRQHandler() { } } - dma_interrupt_flag_clear(DMA0, DMA_CH1, DMA_INTERRUPT_FLAG_CLEAR); + dma_interrupt_flag_clear(DMA0, DMA_CH3, DMA_INTERRUPT_FLAG_CLEAR); } # else -void DMA0_Channel3_IRQHandler() { - if (dma_interrupt_flag_get(DMA0, DMA_CH3, DMA_INTERRUPT_FLAG_GET) == SET) { - dma_interrupt_disable(DMA0, DMA_CH3, DMA_INTERRUPT_DISABLE); +void DMA0_Channel1_IRQHandler() { + if (dma_interrupt_flag_get(DMA0, DMA_CH1, DMA_INTERRUPT_FLAG_GET) == SET) { + dma_interrupt_disable(DMA0, DMA_CH1, DMA_INTERRUPT_DISABLE); + + usart_flag_clear(USART2, USART_FLAG_TC); if (s_TxBuffer[dmx::config::USART2_PORT].outputStyle == dmx::OutputStyle::DELTA) { s_TxBuffer[dmx::config::USART2_PORT].State = TxRxState::IDLE; @@ -1421,7 +1494,7 @@ void DMA0_Channel3_IRQHandler() { } } - dma_interrupt_flag_clear(DMA0, DMA_CH3, DMA_INTERRUPT_FLAG_CLEAR); + dma_interrupt_flag_clear(DMA0, DMA_CH1, DMA_INTERRUPT_FLAG_CLEAR); } # endif #endif @@ -1429,36 +1502,35 @@ void DMA0_Channel3_IRQHandler() { * UART 3 */ #if defined (DMX_USE_UART3) -# if !defined (GD32F4XX) -void DMA1_Channel4_IRQHandler() { - if (dma_interrupt_flag_get(DMA1, DMA_CH4, DMA_INTERRUPT_FLAG_GET) == SET) { - dma_interrupt_disable(DMA1, DMA_CH4, DMA_INTERRUPT_DISABLE); +# if defined (GD32F4XX) || defined (GD32H7XX) +void DMA0_Channel4_IRQHandler() { + if (dma_interrupt_flag_get(DMA0, DMA_CH4, DMA_INTERRUPT_FLAG_GET) == SET) { + dma_interrupt_disable(DMA0, DMA_CH4, DMA_INTERRUPT_DISABLE); if (s_TxBuffer[dmx::config::UART3_PORT].outputStyle == dmx::OutputStyle::DELTA) { s_TxBuffer[dmx::config::UART3_PORT].State = TxRxState::IDLE; } else { - timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_3 , TIMER_CNT(TIMER1) + s_nDmxTransmitInterTime); + timer_channel_output_pulse_value_config(TIMER4, TIMER_CH_3 , TIMER_CNT(TIMER4) + s_nDmxTransmitInterTime); s_TxBuffer[dmx::config::UART3_PORT].State = TxRxState::DMXINTER; } } - dma_interrupt_flag_clear(DMA1, DMA_CH4, DMA_INTERRUPT_FLAG_CLEAR); + dma_interrupt_flag_clear(DMA0, DMA_CH4, DMA_INTERRUPT_FLAG_CLEAR); } -# endif -# if defined (GD32F4XX) -void DMA0_Channel4_IRQHandler() { - if (dma_interrupt_flag_get(DMA0, DMA_CH4, DMA_INTERRUPT_FLAG_GET) == SET) { - dma_interrupt_disable(DMA0, DMA_CH4, DMA_INTERRUPT_DISABLE); +# else +void DMA1_Channel4_IRQHandler() { + if (dma_interrupt_flag_get(DMA1, DMA_CH4, DMA_INTERRUPT_FLAG_GET) == SET) { + dma_interrupt_disable(DMA1, DMA_CH4, DMA_INTERRUPT_DISABLE); if (s_TxBuffer[dmx::config::UART3_PORT].outputStyle == dmx::OutputStyle::DELTA) { s_TxBuffer[dmx::config::UART3_PORT].State = TxRxState::IDLE; } else { - timer_channel_output_pulse_value_config(TIMER4, TIMER_CH_3 , TIMER_CNT(TIMER4) + s_nDmxTransmitInterTime); + timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_3 , TIMER_CNT(TIMER1) + s_nDmxTransmitInterTime); s_TxBuffer[dmx::config::UART3_PORT].State = TxRxState::DMXINTER; } } - dma_interrupt_flag_clear(DMA0, DMA_CH4, DMA_INTERRUPT_FLAG_CLEAR); + dma_interrupt_flag_clear(DMA1, DMA_CH4, DMA_INTERRUPT_FLAG_CLEAR); } # endif #endif @@ -1482,7 +1554,7 @@ void DMA1_Channel3_IRQHandler() { dma_interrupt_flag_clear(DMA1, DMA_CH3, DMA_INTERRUPT_FLAG_CLEAR); } # endif -# if defined (GD32F4XX) +# if defined (GD32F4XX) || defined (GD32H7XX) void DMA0_Channel7_IRQHandler() { if (dma_interrupt_flag_get(DMA0, DMA_CH7, DMA_INTERRUPT_FLAG_GET) == SET) { dma_interrupt_disable(DMA0, DMA_CH7, DMA_INTERRUPT_DISABLE); @@ -1538,7 +1610,7 @@ void DMA1_Channel4_IRQHandler() { dma_interrupt_flag_clear(DMA1, DMA_CH4, DMA_INTERRUPT_FLAG_CLEAR); } # endif -# if defined (GD32F4XX) +# if defined (GD32F4XX) || defined (GD32H7XX) void DMA0_Channel1_IRQHandler() { if (dma_interrupt_flag_get(DMA0, DMA_CH1, DMA_INTERRUPT_FLAG_GET) == SET) { dma_interrupt_disable(DMA0, DMA_CH1, DMA_INTERRUPT_DISABLE); @@ -1575,7 +1647,7 @@ void DMA1_Channel3_IRQHandler() { dma_interrupt_flag_clear(DMA1, DMA_CH3, DMA_INTERRUPT_FLAG_CLEAR); } # endif -# if defined (GD32F4XX) +# if defined (GD32F4XX) || defined (GD32H7XX) void DMA0_Channel0_IRQHandler() { if (dma_interrupt_flag_get(DMA0, DMA_CH0, DMA_INTERRUPT_FLAG_GET) == SET) { dma_interrupt_disable(DMA0, DMA_CH0, DMA_INTERRUPT_DISABLE); @@ -1598,7 +1670,7 @@ static void uart_dmx_config(uint32_t usart_periph) { gd32_uart_begin(usart_periph, 250000U, GD32_UART_BITS_8, GD32_UART_PARITY_NONE, GD32_UART_STOP_2BITS); } -Dmx *Dmx::s_pThis = nullptr; +Dmx *Dmx::s_pThis; Dmx::Dmx() { DEBUG_ENTRY @@ -1611,11 +1683,11 @@ Dmx::Dmx() { s_nDmxTransmitInterTime = dmx::transmit::PERIOD_DEFAULT - s_nDmxTransmitBreakTime - s_nDmxTransmitMabTime - (dmx::max::CHANNELS * 44) - 44; for (auto i = 0; i < DMX_MAX_PORTS; i++) { -#if !defined (GD32F4XX) +#if defined (GPIO_INIT) gpio_init(s_DirGpio[i].nPort, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, s_DirGpio[i].nPin); #else gpio_mode_set(s_DirGpio[i].nPort, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLDOWN, s_DirGpio[i].nPin); - gpio_output_options_set(s_DirGpio[i].nPort, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, s_DirGpio[i].nPin); + gpio_output_options_set(s_DirGpio[i].nPort, GPIO_OTYPE_PP, GPIO_OSPEED, s_DirGpio[i].nPin); gpio_af_set(s_DirGpio[i].nPort, GPIO_AF_0, s_DirGpio[i].nPin); #endif m_nDmxTransmissionLength[i] = dmx::max::CHANNELS; @@ -1676,7 +1748,6 @@ Dmx::Dmx() { } void Dmx::SetPortDirection(const uint32_t nPortIndex, PortDirection portDirection, bool bEnableData) { -// DEBUG_PRINTF("nPortIndex=%u %s %c", nPortIndex, portDirection == PortDirection::INP ? "Input" : "Output", bEnableData ? 'Y' : 'N'); assert(nPortIndex < DMX_MAX_PORTS); const auto nUart = _port_to_uart(nPortIndex); @@ -1716,8 +1787,6 @@ void Dmx::ClearData(const uint32_t nPortIndex) { } void Dmx::StartDmxOutput(const uint32_t nPortIndex) { - logic_analyzer::ch2_set(); - assert(nPortIndex < dmx::config::max::OUT); const auto nUart = _port_to_uart(nPortIndex); @@ -1803,8 +1872,6 @@ void Dmx::StartDmxOutput(const uint32_t nPortIndex) { } s_TxBuffer[nPortIndex].State = TxRxState::BREAK; - - logic_analyzer::ch2_clear(); } @@ -1908,8 +1975,9 @@ void Dmx::SetDmxPeriodTime(uint32_t nPeriod) { auto nPackageLengthMicroSeconds = s_nDmxTransmitBreakTime + s_nDmxTransmitMabTime + (nLengthMax * 44U); - // The GD32F4xx Timer 1 has a 32-bit counter -#if ! defined(GD32F4XX) + // The GD32F4xx/GD32H7XX Timer 1 has a 32-bit counter +#if defined(GD32F4XX) || defined (GD32H7XX) +#else if (nPackageLengthMicroSeconds > (static_cast(~0) - 44U)) { s_nDmxTransmitBreakTime = std::min(transmit::BREAK_TIME_TYPICAL, s_nDmxTransmitBreakTime); s_nDmxTransmitMabTime = transmit::MAB_TIME_MIN; @@ -1949,7 +2017,6 @@ void Dmx::SetDmxSlots(uint16_t nSlots) { void Dmx::SetOutputStyle(const uint32_t nPortIndex, const dmx::OutputStyle outputStyle) { assert(nPortIndex < dmx::config::max::OUT); - s_TxBuffer[nPortIndex].outputStyle = outputStyle; } @@ -1976,8 +2043,6 @@ void Dmx::SetSendData(const uint32_t nPortIndex, const uint8_t *pData, uint32_t } void Dmx::SetSendDataWithoutSC(const uint32_t nPortIndex, const uint8_t *pData, uint32_t nLength) { - logic_analyzer::ch0_set(); - assert(nPortIndex < DMX_MAX_PORTS); auto *p = &s_TxBuffer[nPortIndex]; @@ -1993,8 +2058,6 @@ void Dmx::SetSendDataWithoutSC(const uint32_t nPortIndex, const uint8_t *pData, m_nDmxTransmissionLength[nPortIndex] = nLength; SetDmxPeriodTime(m_nDmxTransmitPeriodRequested); } - - logic_analyzer::ch0_clear(); } void Dmx::Blackout() { @@ -2051,8 +2114,6 @@ void Dmx::StartOutput(const uint32_t nPortIndex) { static bool s_doForce; void Dmx::SetOutput(const bool doForce) { - logic_analyzer::ch1_set(); - if (doForce) { s_doForce = true; for (uint32_t nPortIndex = 0; nPortIndex < dmx::config::max::OUT; nPortIndex++) { @@ -2061,8 +2122,6 @@ void Dmx::SetOutput(const bool doForce) { StopData(_port_to_uart(nPortIndex), nPortIndex); } } - - logic_analyzer::ch1_clear(); return; } @@ -2076,11 +2135,9 @@ void Dmx::SetOutput(const bool doForce) { } s_doForce = false; - logic_analyzer::ch1_clear(); } void Dmx::StartData(const uint32_t nUart, const uint32_t nPortIndex) { -// DEBUG_PRINTF("sv_PortState[%u]=%u", nPortIndex, sv_PortState[nPortIndex]); assert(nPortIndex < DMX_MAX_PORTS); assert(sv_PortState[nPortIndex] == PortState::IDLE); @@ -2155,7 +2212,7 @@ void Dmx::StartData(const uint32_t nUart, const uint32_t nPortIndex) { // DMX Receive -const uint8_t* Dmx::GetDmxChanged(UNUSED uint32_t nPortIndex) { +const uint8_t *Dmx::GetDmxChanged(UNUSED uint32_t nPortIndex) { #if !defined(CONFIG_DMX_TRANSMIT_ONLY) const auto *p = GetDmxAvailable(nPortIndex); @@ -2342,11 +2399,19 @@ void Dmx::RdmSendRaw(const uint32_t nPortIndex, const uint8_t* pRdmData, uint32_ for (uint32_t i = 0; i < nLength; i++) { while (RESET == usart_flag_get(nUart, USART_FLAG_TBE)) ; +#if defined (GD32H7XX) + USART_TDATA(nUart) = USART_TDATA_TDATA & pRdmData[i]; +#else USART_DATA(nUart) = static_cast(USART_DATA_DATA & pRdmData[i]); +#endif } while (SET != usart_flag_get(nUart, USART_FLAG_TC)) { +#if defined (GD32H7XX) + static_cast(GET_BITS(USART_RDATA(nUart), 0U, 8U)); +#else static_cast(GET_BITS(USART_DATA(nUart), 0U, 8U)); +#endif } } @@ -2366,11 +2431,19 @@ void Dmx::RdmSendDiscoveryRespondMessage(uint32_t nPortIndex, const uint8_t *pRd for (uint32_t i = 0; i < nLength; i++) { while (RESET == usart_flag_get(nUart, USART_FLAG_TBE)) ; +#if defined (GD32H7XX) + USART_TDATA(nUart) = USART_TDATA_TDATA & pRdmData[i]; +#else USART_DATA(nUart) = static_cast(USART_DATA_DATA & pRdmData[i]); +#endif } while (SET != usart_flag_get(nUart, USART_FLAG_TC)) { +#if defined (GD32H7XX) + static_cast(GET_BITS(USART_RDATA(nUart), 0U, 8U)); +#else static_cast(GET_BITS(USART_DATA(nUart), 0U, 8U)); +#endif } udelay(RDM_RESPONDER_DATA_DIRECTION_DELAY); diff --git a/lib-dmx/src/gd32/dmx_internal.h b/lib-dmx/src/gd32/dmx_internal.h index 8a6dd88..da66b21 100644 --- a/lib-dmx/src/gd32/dmx_internal.h +++ b/lib-dmx/src/gd32/dmx_internal.h @@ -2,7 +2,7 @@ * @file dmx_internal.h * */ -/* Copyright (C) 2021-2022 by Arjan van Vught mailto:info@gd32-dmx.org +/* Copyright (C) 2021-2024 by Arjan van Vught mailto:info@gd32-dmx.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -32,7 +32,7 @@ #include "gd32.h" #include "gd32/dmx_config.h" -static uint32_t _port_to_uart(const uint32_t nPort) { +inline uint32_t _port_to_uart(const uint32_t nPort) { switch (nPort) { #if defined (DMX_USE_USART0) case dmx::config::USART0_PORT: @@ -85,46 +85,80 @@ static uint32_t _port_to_uart(const uint32_t nPort) { return 0; } -#if defined (GD32F4XX) +#if defined (GD32F4XX) || defined (GD32H7XX) // GPIO -static void _gpio_mode_output(uint32_t gpio_periph, uint32_t pin) { - gpio_af_set(gpio_periph, GPIO_AF_0, pin); //TODO This needs some research. Is it really needed? - gpio_mode_set(gpio_periph, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, pin); +void gd32_gpio_mode_set_output(const uint32_t gpio_periph, const uint32_t pin); +void gd32_gpio_mode_set_af(const uint32_t gpio_periph, const uint32_t pin); + +inline void gd32_gpio_af_set(const uint32_t gpio_periph, const uint32_t alt_func_num, const uint32_t pin) { + auto afrl = GPIO_AFSEL0(gpio_periph); + auto afrh = GPIO_AFSEL1(gpio_periph); + + for (uint32_t i = 0U; i < 8U; i++) { + if ((1U << i) & pin) { + /* clear the specified pin alternate function bits */ + afrl &= ~GPIO_AFR_MASK(i); + afrl |= GPIO_AFR_SET(i, alt_func_num); + } + } + + for (uint32_t i = 8U; i < 16U; i++) { + if ((1U << i) & pin) { + /* clear the specified pin alternate function bits */ + afrh &= ~GPIO_AFR_MASK(i - 8U); + afrh |= GPIO_AFR_SET(i - 8U, alt_func_num); + } + } + + GPIO_AFSEL0(gpio_periph) = afrl; + GPIO_AFSEL1(gpio_periph) = afrh; +} + +inline void _gpio_mode_output(const uint32_t gpio_periph, const uint32_t pin) { + gd32_gpio_mode_set_output(gpio_periph, pin); } -static void _gpio_mode_af(const uint32_t gpio_periph, uint32_t pin, const uint32_t usart_periph) { - gpio_mode_set(gpio_periph, GPIO_MODE_AF, GPIO_PUPD_PULLUP, pin); +inline void _gpio_mode_af(const uint32_t gpio_periph, const uint32_t pin, const uint32_t usart_periph) { + gd32_gpio_mode_set_af(gpio_periph, pin); switch (usart_periph) { #if defined (DMX_USE_USART0) case USART0: + gpio_af_set(gpio_periph, USART0_GPIO_AF, pin); + break; #endif #if defined (DMX_USE_USART1) case USART1: + gpio_af_set(gpio_periph, USART1_GPIO_AF, pin); + break; #endif #if defined (DMX_USE_USART2) case USART2: -#endif -#if defined (DMX_USE_USART0) || defined (DMX_USE_USART1) || defined(DMX_USE_USART2) - gpio_af_set(gpio_periph, GPIO_AF_7, pin); + gpio_af_set(gpio_periph, USART2_GPIO_AF, pin); break; #endif #if defined (DMX_USE_UART3) case UART3: + gpio_af_set(gpio_periph, UART3_GPIO_AF, pin); + break; #endif #if defined (DMX_USE_UART4) case UART4: + gpio_af_set(gpio_periph, UART4_GPIO_AF, pin); + break; #endif #if defined (DMX_USE_USART5) case USART5: + gd32_gpio_af_set(gpio_periph, USART5_GPIO_AF, pin); + break; #endif #if defined (DMX_USE_UART6) case UART6: + gpio_af_set(gpio_periph, UART6_GPIO_AF, pin); + break; #endif #if defined (DMX_USE_UART7) case UART7: -#endif -#if defined (DMX_USE_UART3) || defined (DMX_USE_UART4) || defined(DMX_USE_USART5) || defined (DMX_USE_UART6) || defined (DMX_USE_UART7) - gpio_af_set(gpio_periph, GPIO_AF_8, pin); + gpio_af_set(gpio_periph, UART7_GPIO_AF, pin); break; #endif default: @@ -146,10 +180,10 @@ static void _gpio_mode_af(const uint32_t gpio_periph, uint32_t pin, const uint32 # define DMA_INTERRUPT_FLAG_CLEAR (DMA_INT_FLAG_FTF | DMA_INT_FLAG_TAE) #else // GPIO -static void _gpio_mode_output(uint32_t gpio_periph, uint32_t pin) { +inline void _gpio_mode_output(const uint32_t gpio_periph, const uint32_t pin) { gpio_init(gpio_periph, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, pin); } -static void _gpio_mode_af(uint32_t gpio_periph, uint32_t pin, __attribute__((unused)) const uint32_t usart_periph ) { +inline void _gpio_mode_af(const uint32_t gpio_periph, const uint32_t pin, [[maybe_unused]] const uint32_t usart_periph ) { gpio_init(gpio_periph, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, pin); } // DMA diff --git a/lib-flashcode/Makefile.GD32 b/lib-flashcode/Makefile.GD32 index e0ac745..3808855 100755 --- a/lib-flashcode/Makefile.GD32 +++ b/lib-flashcode/Makefile.GD32 @@ -4,7 +4,11 @@ ifneq ($(MAKE_FLAGS),) ifeq ($(findstring gd32f4xx,$(FAMILY)), gd32f4xx) EXTRA_SRCDIR=src/gd32/f4xx else - EXTRA_SRCDIR=src/gd32/fmc + ifeq ($(findstring gd32h7xx,$(FAMILY)), gd32h7xx) + EXTRA_SRCDIR=src/gd32/h7xx + else + EXTRA_SRCDIR=src/gd32/fmc + endif endif else EXTRA_SRCDIR=src/gd32/fmc diff --git a/lib-flashcode/src/gd32/h7xx/flashcode.cpp b/lib-flashcode/src/gd32/h7xx/flashcode.cpp new file mode 100644 index 0000000..47cc26a --- /dev/null +++ b/lib-flashcode/src/gd32/h7xx/flashcode.cpp @@ -0,0 +1,217 @@ +/** + * @file flashcode.cpp + * + */ +/* Copyright (C) 2024 by Arjan van Vught mailto:info@gd32-dmx.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "flashcode.h" + +#include "gd32.h" + +#include "debug.h" + +namespace flashcode { +/* Backwards compatibility with SPI FLASH */ +static constexpr auto FLASH_SECTOR_SIZE = 4096U; +/* The flash page size is 4KB for bank1 */ +static constexpr auto BANK1_FLASH_PAGE = (4U * 1024U); + +enum class State { + IDLE, + ERASE_BUSY, + ERASE_PROGAM, + WRITE_BUSY, + WRITE_PROGRAM, + ERROR +}; + +static State s_State = State::IDLE; +static uint32_t s_nPage; +static uint32_t s_nLength; +static uint32_t s_nAddress; +static uint32_t *s_pData; +} // namespace flashcode + +using namespace flashcode; + +uint32_t FlashCode::GetSize() const { + const auto FLASH_DENSITY = ((REG32(0x1FF0F7E0) >> 16) & 0xFFFF) * 1024U; + return FLASH_DENSITY; +} + +uint32_t FlashCode::GetSectorSize() const { + return flashcode::FLASH_SECTOR_SIZE; +} + +bool FlashCode::Read(uint32_t nOffset, uint32_t nLength, uint8_t *pBuffer, flashcode::result& nResult) { + DEBUG_ENTRY + DEBUG_PRINTF("offset=%p[%d], len=%u[%d], data=%p[%d]", nOffset, (((uint32_t)(nOffset) & 0x3) == 0), nLength, (((uint32_t)(nLength) & 0x3) == 0), pBuffer, (((uint32_t)(pBuffer) & 0x3) == 0)); + + const auto *pSrc = reinterpret_cast(nOffset + FLASH_BASE); + auto *pDst = reinterpret_cast(pBuffer); + + while (nLength > 0) { + *pDst++ = *pSrc++; + nLength -= 4; + } + + nResult = flashcode::result::OK; + + DEBUG_EXIT + return true; +} + +bool FlashCode::Erase(uint32_t nOffset, uint32_t nLength, flashcode::result& nResult) { + DEBUG_ENTRY + DEBUG_PRINTF("State=%d", static_cast(s_State)); + + nResult = result::OK; + + switch (s_State) { + case State::IDLE: + s_nPage = nOffset + FLASH_BASE; + s_nLength = nLength; + fmc_unlock(); + s_State = State::ERASE_BUSY; + DEBUG_EXIT + return false; + break; + case State::ERASE_BUSY: + if (SET == fmc_flag_get(FMC_FLAG_BUSY)) { + DEBUG_EXIT + return false; + } + + if (s_nLength == 0) { + s_State = State::IDLE; + fmc_lock(); + DEBUG_EXIT + return true; + } + + s_State = State::ERASE_PROGAM; + DEBUG_EXIT + return false; + break; + case State::ERASE_PROGAM: + if (s_nLength > 0) { + DEBUG_PRINTF("s_nPage=%p", s_nPage); + + fmc_sector_erase(s_nPage); + + s_nLength -= BANK1_FLASH_PAGE; + s_nPage += BANK1_FLASH_PAGE; + } + + s_State = State::ERASE_BUSY; + DEBUG_EXIT + return false; + break; + default: + assert(0); + __builtin_unreachable(); + break; + } + + assert(0); + __builtin_unreachable(); + return true; +} + +bool FlashCode::Write(uint32_t nOffset, uint32_t nLength, const uint8_t *pBuffer, flashcode::result& nResult) { + if ((s_State == flashcode::State::WRITE_PROGRAM) || (s_State == flashcode::State::WRITE_BUSY)) { + } else { + DEBUG_ENTRY + } + nResult = result::OK; + + switch (s_State) { + case flashcode::State::IDLE: + DEBUG_PUTS("State::IDLE"); + flashcode::s_nAddress = nOffset + FLASH_BASE; + s_pData = const_cast(reinterpret_cast(pBuffer)); + s_nLength = nLength; + fmc_unlock(); + s_State = State::WRITE_BUSY; + DEBUG_EXIT + return false; + break; + case flashcode::State::WRITE_BUSY: + if (SET == fmc_flag_get(FMC_FLAG_BUSY)) { + DEBUG_EXIT + return false; + } + + if (s_nLength == 0) { + fmc_lock(); + s_State = State::IDLE; + + if( memcmp(reinterpret_cast(nOffset + FLASH_BASE), pBuffer, nLength) == 0) { + DEBUG_PUTS("memcmp OK"); + } else { + DEBUG_PUTS("memcmp failed"); + } + + DEBUG_EXIT + return true; + } + + s_State = flashcode::State::WRITE_PROGRAM; + return false; + break; + case flashcode::State::WRITE_PROGRAM: + if (s_nLength >= 4) { + if (FMC_READY == fmc_ready_wait(0xFF)) { + /* set the PG bit to start program */ + FMC_CTL |= FMC_CTL_PG; + __ISB(); + __DSB(); + REG32(s_nAddress) = *s_pData; + __ISB(); + __DSB(); + /* reset the PG bit */ + FMC_CTL &= ~FMC_CTL_PG; + s_pData++; + s_nAddress += 4; + s_nLength -= 4; + } + } else if (s_nLength > 0) { + DEBUG_PUTS("Error!"); + } + s_State = flashcode::State::WRITE_BUSY; + return false; + break; + default: + assert(0); + __builtin_unreachable(); + break; + } + + assert(0); + __builtin_unreachable(); + return true; +} diff --git a/lib-gd32/src/gd32_gpio_mode_set.cpp b/lib-gd32/src/gd32_gpio_mode_set.cpp new file mode 100644 index 0000000..bf8f480 --- /dev/null +++ b/lib-gd32/src/gd32_gpio_mode_set.cpp @@ -0,0 +1,75 @@ +#if defined (GD32F4XX) || defined (GD32H7XX) +/** + * @file gd32_gpio_mode_set.cpp + * + */ +/* Copyright (C) 2024 by Arjan van Vught mailto:info@gd32-dmx.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "gd32.h" + +void gd32_gpio_mode_set_output(const uint32_t gpio_periph, const uint32_t pin) { + assert(pin != 0); + assert(__builtin_popcount(static_cast(pin)) == 1); + + auto ctl = GPIO_CTL(gpio_periph); + auto pupd = GPIO_PUD(gpio_periph); + + const auto i = 31 - __builtin_clz(pin); + + /* clear the specified pin mode bits */ + ctl &= ~GPIO_MODE_MASK(i); + /* set the specified pin mode bits */ + ctl |= GPIO_MODE_SET(i, GPIO_MODE_OUTPUT); + /* clear the specified pin pupd bits */ + pupd &= ~GPIO_PUPD_MASK(i); + /* set the specified pin pupd bits */ + pupd |= GPIO_PUPD_SET(i, GPIO_PUPD_NONE); + + GPIO_CTL(gpio_periph) = ctl; + GPIO_PUD(gpio_periph) = pupd; +} + +void gd32_gpio_mode_set_af(const uint32_t gpio_periph, const uint32_t pin) { + assert(pin != 0); + assert(__builtin_popcount(static_cast(pin)) == 1); + + auto ctl = GPIO_CTL(gpio_periph); + auto pupd = GPIO_PUD(gpio_periph); + + const auto i = 31 - __builtin_clz(pin); + + /* clear the specified pin mode bits */ + ctl &= ~GPIO_MODE_MASK(i); + /* set the specified pin mode bits */ + ctl |= GPIO_MODE_SET(i, GPIO_MODE_AF); + /* clear the specified pin pupd bits */ + pupd &= ~GPIO_PUPD_MASK(i); + /* set the specified pin pupd bits */ + pupd |= GPIO_PUPD_SET(i, GPIO_PUPD_PULLUP); + + GPIO_CTL(gpio_periph) = ctl; + GPIO_PUD(gpio_periph) = pupd; +} +#endif diff --git a/lib-gd32/src/h/gd32_adc.cpp b/lib-gd32/src/h/gd32_adc.cpp deleted file mode 100644 index b5f1c7f..0000000 --- a/lib-gd32/src/h/gd32_adc.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/** - * @file gd32_adc.cpp - * - */ -/* Copyright (C) 2024 by Arjan van Vught mailto:info@gd32-dmx.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include - -#include "gd32.h" - -#define ADC_TEMP_CALIBRATION_VALUE_25 REG16(0x1FF0F7C0) -#define ADC_TEMP_CALIBRATION_VALUE_MINUS40 REG16(0x1FF0F7C2) - -static float avg_slope; -static int32_t temperature_value_25; -static int32_t temperature_value_minus40; - -static void rcu_config() { - /* enable ADC clock */ - rcu_periph_clock_enable(RCU_ADC2); -} - -static void adc_config() { - /* reset ADC */ - adc_deinit(ADC2); - /* ADC clock config */ - adc_clock_config(ADC2, ADC_CLK_SYNC_HCLK_DIV6); - /* ADC contineous function enable */ - adc_special_function_config(ADC2, ADC_CONTINUOUS_MODE, DISABLE); - /* ADC scan mode enable */ - adc_special_function_config(ADC2, ADC_SCAN_MODE, ENABLE); - /* ADC resolution config */ - adc_resolution_config(ADC2, ADC_RESOLUTION_12B); - /* ADC data alignment config */ - adc_data_alignment_config(ADC2, ADC_DATAALIGN_RIGHT); - - /* ADC channel length config */ - adc_channel_length_config(ADC2, ADC_INSERTED_CHANNEL, 2); - - /* ADC temperature sensor channel config */ - adc_inserted_channel_config(ADC2, 0, ADC_CHANNEL_18, 480); - /* ADC internal reference voltage channel config */ - adc_inserted_channel_config(ADC2, 1, ADC_CHANNEL_19, 480); - - /* enable ADC temperature channel */ - adc_internal_channel_config(ADC_CHANNEL_INTERNAL_TEMPSENSOR, ENABLE); - /* enable internal reference voltage channel */ - adc_internal_channel_config(ADC_CHANNEL_INTERNAL_VREFINT, ENABLE); - - /* ADC trigger config */ - adc_external_trigger_config(ADC2, ADC_INSERTED_CHANNEL, EXTERNAL_TRIGGER_DISABLE); - - /* enable ADC interface */ - adc_enable(ADC2); - /* wait for ADC stability */ - udelay(1000); - /* ADC calibration mode config */ - adc_calibration_mode_config(ADC2, ADC_CALIBRATION_OFFSET_MISMATCH); - /* ADC calibration number config */ - adc_calibration_number(ADC2, ADC_CALIBRATION_NUM1); - /* ADC calibration and reset calibration */ - adc_calibration_enable(ADC2); - - /* ADC software trigger enable */ - adc_software_trigger_enable(ADC2, ADC_INSERTED_CHANNEL); -} - -void gd32_adc_init() { - rcu_config(); - adc_config(); - - temperature_value_25 = ADC_TEMP_CALIBRATION_VALUE_25 & 0x0FFF; - temperature_value_minus40 = ADC_TEMP_CALIBRATION_VALUE_MINUS40 & 0x0FFF; - avg_slope = -(temperature_value_25 - temperature_value_minus40) / (25.0f + 40.0f); -} - -float gd32_adc_gettemp() { - const auto temperature = (temperature_value_25 - ADC_IDATA0(ADC2)) * 3.3f / 4096 / avg_slope * 1000 + 25; - adc_software_trigger_enable(ADC2, ADC_INSERTED_CHANNEL); - return temperature; -} - -float gd32_adc_getvref() { - const auto vref_value = (ADC_IDATA1(ADC2) * 3.3f / 4096); - adc_software_trigger_enable(ADC2, ADC_INSERTED_CHANNEL); - return vref_value; -} diff --git a/lib-gd32/src/h/gd32_i2c.cpp b/lib-gd32/src/h/gd32_i2c.cpp deleted file mode 100644 index 17f635e..0000000 --- a/lib-gd32/src/h/gd32_i2c.cpp +++ /dev/null @@ -1,346 +0,0 @@ -/** - * @file gd32_i2c.cpp - * - */ -/* Copyright (C) 2024 by Arjan van Vught mailto:info@gd32-dmx.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include - -#include "gd32_i2c.h" -#include "gd32.h" - -#include "debug.h" - -enum class State { - I2C_START, - I2C_TRANSMIT_DATA, - I2C_RELOAD, - I2C_STOP -}; - -static constexpr uint8_t MAX_RELOAD_SIZE = 255; -static constexpr int32_t I2C_TIME_OUT = 50000; -static uint8_t s_nAddress; - -static void gpio_config() { - rcu_periph_clock_enable(I2C_GPIO_SCL_CLK); - rcu_periph_clock_enable(I2C_GPIO_SDA_CLK); - rcu_periph_clock_enable(I2C_RCU_CLK); - - gpio_af_set(I2C_GPIO_SCL_PORT, I2C_GPIO_AF, I2C_SCL_PIN); - gpio_af_set(I2C_GPIO_SDA_PORT, I2C_GPIO_AF, I2C_SDA_PIN); - - gpio_mode_set(I2C_GPIO_SCL_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, I2C_SCL_PIN); - gpio_output_options_set(I2C_GPIO_SCL_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_60MHZ, I2C_SCL_PIN); - - gpio_mode_set(I2C_GPIO_SDA_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, I2C_SDA_PIN); - gpio_output_options_set(I2C_GPIO_SDA_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_60MHZ, I2C_SDA_PIN); -} - -static void i2c_config() { - rcu_i2c_clock_config(I2C_RCU_IDX, RCU_I2CSRC_IRC64MDIV); - i2c_timing_config(I2CX, 0x0, 0x6, 0); - i2c_master_clock_config(I2CX, 0x26, 0x73); - i2c_enable(I2CX); -} - -/** - * Public API's - */ - -void gd32_i2c_begin() { - gpio_config(); - i2c_config(); -} - -void gd32_i2c_set_baudrate(const uint32_t nBaudrate) { -// TODO -} - -void gd32_i2c_set_address(const uint8_t nAddress) { - s_nAddress = nAddress << 1; -} - -uint8_t gd32_i2c_write(const char *pBuffer, uint32_t nLength) { - I2C_STAT(I2CX) |= I2C_STAT_TBE; - i2c_reload_enable(I2CX); - i2c_automatic_end_disable(I2CX); - i2c_master_addressing(I2CX, s_nAddress, I2C_MASTER_TRANSMIT); - - if (i2c_flag_get(I2CX, I2C_FLAG_I2CBSY)) { - DEBUG_PUTS("I2CBSY"); - } - - auto state = State::I2C_RELOAD; - auto isFirstReload = true; - auto isLastReload = false; - uint32_t nBytesReload; - - while (true) { - switch (state) { - case State::I2C_RELOAD: { - if (nLength > MAX_RELOAD_SIZE) { - nLength = nLength - MAX_RELOAD_SIZE; - nBytesReload = MAX_RELOAD_SIZE; - } else { - nBytesReload = nLength; - isLastReload = true; - } - - if (isFirstReload) { - isFirstReload = false; - - i2c_transfer_byte_number_config(I2CX, nBytesReload); - - if (isLastReload) { - isLastReload = false; - - if (nLength <= MAX_RELOAD_SIZE) { - i2c_reload_disable(I2CX); - i2c_automatic_end_enable(I2CX); - } - } - - i2c_start_on_bus(I2CX); - - auto nTimeout = I2C_TIME_OUT; - while ((!i2c_flag_get(I2CX, I2C_FLAG_TBE)) && (nTimeout > 0)) { - nTimeout--; - } - - if (nTimeout <= 0) { - state = State::I2C_STOP; - continue; - } - } else { - auto nTimeout = I2C_TIME_OUT; - while ((!i2c_flag_get(I2CX, I2C_FLAG_TCR)) && (nTimeout > 0)) { - nTimeout--; - } - - if (nTimeout <= 0) { - state = State::I2C_STOP; - continue; - } - - i2c_transfer_byte_number_config(I2CX, nBytesReload); - - if (nLength <= MAX_RELOAD_SIZE) { - i2c_reload_disable(I2CX); - i2c_automatic_end_enable(I2CX); - } - } - - state = State::I2C_TRANSMIT_DATA; - } - break; - case State::I2C_TRANSMIT_DATA: { - while (nBytesReload) { - auto nTimeout = I2C_TIME_OUT; - while ((!i2c_flag_get(I2CX, I2C_FLAG_TI)) && (nTimeout > 0)) { - nTimeout--; - } - - if (nTimeout <= 0) { - printf(" %u %u\n", (I2C_CTL1(I2CX) >> 16) & 0xFF, nBytesReload); - state = State::I2C_STOP; - break; - } else { - i2c_data_transmit(I2CX, *pBuffer++); - nBytesReload--; - } - } - - if (state == State::I2C_STOP) { - continue; - } - - if (I2C_CTL1(I2CX) & I2C_CTL1_RELOAD) { - state = State::I2C_RELOAD; - } else { - state = State::I2C_STOP; - } - } - break; - case State::I2C_STOP: { - auto nTimeout = I2C_TIME_OUT; - while ((!i2c_flag_get(I2CX, I2C_FLAG_STPDET)) && (nTimeout > 0)) { - nTimeout--; - } - - if (nTimeout <= 0) { - return GD32_I2C_NOK_TOUT; - } - - i2c_flag_clear(I2CX, I2C_FLAG_STPDET); - - if (i2c_flag_get(I2CX, I2C_FLAG_NACK)) { - i2c_flag_clear(I2CX, I2C_FLAG_NACK); - return GD32_I2C_NACK; - } - - return GD32_I2C_OK; - } - break; - default: - assert(0); - break; - } - } - - assert(0); - return GD32_I2C_NOK; -} - -uint8_t gd32_i2c_read(char *pBuffer, uint32_t nLength) { - I2C_STAT(I2CX) |= I2C_STAT_TBE; - i2c_reload_enable(I2CX); - i2c_automatic_end_disable(I2CX); - i2c_master_addressing(I2CX, s_nAddress, I2C_MASTER_RECEIVE); - - if (i2c_flag_get(I2CX, I2C_FLAG_I2CBSY)) { - DEBUG_PUTS("I2CBSY"); - } - - auto state = State::I2C_RELOAD; - auto isFirstReload = true; - auto isLastReload = false; - uint32_t nBytesReload; - - while (true) { - switch (state) { - case State::I2C_RELOAD: { - if (nLength > MAX_RELOAD_SIZE) { - nLength = nLength - MAX_RELOAD_SIZE; - nBytesReload = MAX_RELOAD_SIZE; - } else { - nBytesReload = nLength; - isLastReload = true; - } - - if (isFirstReload) { - isFirstReload = false; - - i2c_transfer_byte_number_config(I2CX, nBytesReload); - - if (isLastReload) { - isLastReload = false; - - if (nLength <= MAX_RELOAD_SIZE) { - i2c_reload_disable(I2CX); - i2c_automatic_end_enable(I2CX); - } - } - - i2c_start_on_bus(I2CX); - - auto nTimeout = I2C_TIME_OUT; - while ((!i2c_flag_get(I2CX, I2C_FLAG_TBE)) && (nTimeout > 0)) { - nTimeout--; - } - - if (nTimeout <= 0) { - state = State::I2C_STOP; - continue; - } - } else { - auto nTimeout = I2C_TIME_OUT; - while ((!i2c_flag_get(I2CX, I2C_FLAG_TCR)) && (nTimeout > 0)) { - nTimeout--; - } - - if (nTimeout <= 0) { - state = State::I2C_STOP; - continue; - } - - i2c_transfer_byte_number_config(I2CX, nBytesReload); - - if (nLength <= MAX_RELOAD_SIZE) { - i2c_reload_disable(I2CX); - i2c_automatic_end_enable(I2CX); - } - } - - state = State::I2C_TRANSMIT_DATA; - } - break; - case State::I2C_TRANSMIT_DATA: { - while (nBytesReload) { - auto nTimeout = I2C_TIME_OUT; - while ((!i2c_flag_get(I2CX, I2C_FLAG_RBNE)) && (nTimeout > 0)) { - if (i2c_flag_get(I2CX, I2C_FLAG_NACK)) { - state = State::I2C_STOP; - break; - } - nTimeout--; - } - - if (nTimeout <= 0) { - state = State::I2C_STOP; - break; - } - - *pBuffer++ = i2c_data_receive(I2CX); - nBytesReload--; - } - - if (state == State::I2C_STOP) { - continue; - } - - if (I2C_CTL1(I2CX) & I2C_CTL1_RELOAD) { - state = State::I2C_RELOAD; - } else { - state = State::I2C_STOP; - } - } - break; - case State::I2C_STOP: { - auto nTimeout = I2C_TIME_OUT; - while ((!i2c_flag_get(I2CX, I2C_FLAG_STPDET)) && (nTimeout > 0)) { - nTimeout--; - } - - if (nTimeout <= 0) { - return GD32_I2C_NOK_TOUT; - } - - i2c_flag_clear(I2CX, I2C_FLAG_STPDET); - - if (i2c_flag_get(I2CX, I2C_FLAG_NACK)) { - i2c_flag_clear(I2CX, I2C_FLAG_NACK); - return GD32_I2C_NACK; - } - - return GD32_I2C_OK; - } - break; - default: - assert(0); - break; - } - } - - assert(0); - return GD32_I2C_NOK; -}