From 2881c2ff2a3e708f948ff661033de9ab75364ae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 14 Jan 2018 21:44:11 +0100 Subject: [PATCH] almost finished DMA reception --- framework/rsc_enum.h | 2 +- gex.mk | 2 +- platform/hw_utils.h | 43 +++ platform/irq_dispatcher.c | 377 +++++++++++++++++++++++ platform/irq_dispatcher.h | 39 +++ platform/plat_init.c | 2 + stm32_assert.c | 26 +- stm32_assert.h | 41 ++- units/usart/_dmas.c | 255 ++++++++++++++++ units/usart/_init.c | 343 +++++++++++++++++++++ units/usart/_internal.h | 56 ++++ units/usart/_settings_bin.c | 74 +++++ units/usart/_settings_ini.c | 168 +++++++++++ units/usart/unit_usart.c | 578 +----------------------------------- utils/malloc_safe.c | 8 +- 15 files changed, 1405 insertions(+), 609 deletions(-) create mode 100644 platform/irq_dispatcher.c create mode 100644 platform/irq_dispatcher.h create mode 100644 units/usart/_dmas.c create mode 100644 units/usart/_init.c create mode 100644 units/usart/_internal.h create mode 100644 units/usart/_settings_bin.c create mode 100644 units/usart/_settings_ini.c diff --git a/framework/rsc_enum.h b/framework/rsc_enum.h index b0a96b3..6854825 100644 --- a/framework/rsc_enum.h +++ b/framework/rsc_enum.h @@ -64,7 +64,7 @@ // - some support quadrature input, probably all support external clock / gating / clock-out/PWM generation // Not all chips have all timers and not all timers are equal. -// DMA - Direct memory access lines - TODO split those to channels, they can be used separately +// DMA - Direct memory access lines // The resource registry will be pre-loaded with platform-specific config of which blocks are available - the rest will be "pre-claimed" // (i.e. unavailable to functional modules) diff --git a/gex.mk b/gex.mk index 2989aae..84ff98e 100644 --- a/gex.mk +++ b/gex.mk @@ -5,7 +5,6 @@ GEX_SRC_DIR = \ User/framework \ User/platform \ User/units \ - User/units/system \ User/units/neopixel \ User/units/test \ User/units/digital_out \ @@ -35,6 +34,7 @@ GEX_INCLUDES = \ -IUser/TinyFrame \ -IUser/vfs \ -IUser/utils \ + -IUser/units \ -IUser/framework \ -IUser/platform \ -IUser/tasks \ diff --git a/platform/hw_utils.h b/platform/hw_utils.h index dc427c1..aefeeb3 100644 --- a/platform/hw_utils.h +++ b/platform/hw_utils.h @@ -7,6 +7,7 @@ #ifndef GEX_PIN_UTILS_H #define GEX_PIN_UTILS_H +#include #include "platform.h" #include "resources.h" @@ -147,4 +148,46 @@ void hw_periph_clock_enable(void *periph); */ void hw_periph_clock_disable(void *periph); +// ---------- LL extras ------------ + +static inline bool LL_DMA_IsActiveFlag_G(uint32_t isr_snapshot, uint8_t channel) +{ + return 0 != (isr_snapshot & (DMA_ISR_GIF1 << (uint32_t)((channel-1) * 4))); +} + +static inline bool LL_DMA_IsActiveFlag_TC(uint32_t isr_snapshot, uint8_t channel) +{ + return 0 != (isr_snapshot & (DMA_ISR_TCIF1 << (uint32_t)((channel-1) * 4))); +} + +static inline bool LL_DMA_IsActiveFlag_HT(uint32_t isr_snapshot, uint8_t channel) +{ + return 0 != (isr_snapshot & (DMA_ISR_HTIF1 << (uint32_t)((channel-1) * 4))); +} + +static inline bool LL_DMA_IsActiveFlag_TE(uint32_t isr_snapshot, uint8_t channel) +{ + return 0 != (isr_snapshot & (DMA_ISR_TEIF1 << (uint32_t)((channel-1) * 4))); +} + +static inline void LL_DMA_ClearFlag_HT(DMA_TypeDef *DMAx, uint8_t channel) +{ + DMAx->IFCR = (DMA_IFCR_CHTIF1 << (uint32_t)((channel-1) * 4)); +} + +static inline void LL_DMA_ClearFlag_TC(DMA_TypeDef *DMAx, uint8_t channel) +{ + DMAx->IFCR = (DMA_IFCR_CTCIF1 << (uint32_t)((channel-1) * 4)); +} + +static inline void LL_DMA_ClearFlag_TE(DMA_TypeDef *DMAx, uint8_t channel) +{ + DMAx->IFCR = (DMA_IFCR_CTEIF1 << (uint32_t)((channel-1) * 4)); +} + +static inline void LL_DMA_ClearFlags(DMA_TypeDef *DMAx, uint8_t channel) +{ + DMAx->IFCR = (DMA_IFCR_CGIF1 << (uint32_t)((channel-1) * 4)); +} + #endif //GEX_PIN_UTILS_H diff --git a/platform/irq_dispatcher.c b/platform/irq_dispatcher.c new file mode 100644 index 0000000..cb9921e --- /dev/null +++ b/platform/irq_dispatcher.c @@ -0,0 +1,377 @@ +// +// Created by MightyPork on 2018/01/14. +// + +#include +#include "platform.h" +#include "irq_dispatcher.h" + +void irqd_init(void) +{ +// NVIC_EnableIRQ(WWDG_IRQn); /*!< Window WatchDog Interrupt */ +// NVIC_EnableIRQ(PVD_VDDIO2_IRQn); /*!< PVD & VDDIO2 Interrupt through EXTI Lines 16 and 31 */ +// NVIC_EnableIRQ(RTC_IRQn); /*!< RTC Interrupt through EXTI Lines 17, 19 and 20 */ +// NVIC_EnableIRQ(FLASH_IRQn); /*!< FLASH global Interrupt */ +// NVIC_EnableIRQ(RCC_CRS_IRQn); /*!< RCC & CRS global Interrupt */ +// NVIC_EnableIRQ(EXTI0_1_IRQn); /*!< EXTI Line 0 and 1 Interrupt */ +// NVIC_EnableIRQ(EXTI2_3_IRQn); /*!< EXTI Line 2 and 3 Interrupt */ +// NVIC_EnableIRQ(EXTI4_15_IRQn); /*!< EXTI Line 4 to 15 Interrupt */ +// NVIC_EnableIRQ(TSC_IRQn); /*!< Touch Sensing Controller Interrupts */ + NVIC_EnableIRQ(DMA1_Channel1_IRQn); /*!< DMA1 Channel 1 Interrupt */ + NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); /*!< DMA1 Channel 2 and Channel 3 Interrupt */ + NVIC_EnableIRQ(DMA1_Channel4_5_6_7_IRQn); /*!< DMA1 Channel 4 to Channel 7 Interrupt */ + HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 3, 0); + HAL_NVIC_SetPriority(DMA1_Channel2_3_IRQn, 3, 0); + HAL_NVIC_SetPriority(DMA1_Channel4_5_6_7_IRQn, 3, 0); +// NVIC_EnableIRQ(ADC1_COMP_IRQn); /*!< ADC1 and COMP interrupts (ADC interrupt combined with EXTI Lines 21 and 22 */ +// NVIC_EnableIRQ(TIM2_IRQn); /*!< TIM2 global Interrupt */ +// NVIC_EnableIRQ(TIM3_IRQn); /*!< TIM3 global Interrupt */ +// NVIC_EnableIRQ(TIM6_DAC_IRQn); /*!< TIM6 global and DAC channel underrun error Interrupt */ +// NVIC_EnableIRQ(TIM7_IRQn); /*!< TIM7 global Interrupt */ +// NVIC_EnableIRQ(TIM14_IRQn); /*!< TIM14 global Interrupt */ +// NVIC_EnableIRQ(TIM15_IRQn); /*!< TIM15 global Interrupt */ +// NVIC_EnableIRQ(TIM16_IRQn); /*!< TIM16 global Interrupt */ +// NVIC_EnableIRQ(TIM17_IRQn); /*!< TIM17 global Interrupt */ +// NVIC_EnableIRQ(I2C1_IRQn); /*!< I2C1 Event Interrupt & EXTI Line23 Interrupt (I2C1 wakeup) */ +// NVIC_EnableIRQ(I2C2_IRQn); /*!< I2C2 Event Interrupt */ +// NVIC_EnableIRQ(SPI1_IRQn); /*!< SPI1 global Interrupt */ +// NVIC_EnableIRQ(SPI2_IRQn); /*!< SPI2 global Interrupt */ + NVIC_EnableIRQ(USART1_IRQn); /*!< USART1 global Interrupt & EXTI Line25 Interrupt (USART1 wakeup) */ + NVIC_EnableIRQ(USART2_IRQn); /*!< USART2 global Interrupt & EXTI Line26 Interrupt (USART2 wakeup) */ + NVIC_EnableIRQ(USART3_4_IRQn); /*!< USART3 and USART4 global Interrupt */ + HAL_NVIC_SetPriority(USART1_IRQn, 3, 0); + HAL_NVIC_SetPriority(USART2_IRQn, 3, 0); + HAL_NVIC_SetPriority(USART3_4_IRQn, 3, 0); +// NVIC_EnableIRQ(CEC_CAN_IRQn); /*!< CEC and CAN global Interrupts & EXTI Line27 Interrupt */ + +// NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn); /*!< TIM1 Break, Update, Trigger and Commutation Interrupt */ // - handled by hal msp init +// NVIC_EnableIRQ(TIM1_CC_IRQn); /*!< TIM1 Capture Compare Interrupt */ +// NVIC_EnableIRQ(USB_IRQn); /*!< USB global Interrupt & EXTI Line18 Interrupt */ // - USB IRQ is handled by the USB library +} + +//void Default_Handler(void) +//{ +// warn("Missing IRQHandler, ISPR[0]=0x%p", (void*)NVIC->ISPR[0]); +//} + +struct cbslot { + IrqCallback callback; + void *arg; +}; + +static struct callbacks_ { + struct cbslot usart1; + struct cbslot usart2; + struct cbslot usart3; +#ifdef USART4 + struct cbslot usart4; +#endif +#ifdef USART5 + struct cbslot usart5; +#endif + struct cbslot dma1_1; + struct cbslot dma1_2; + struct cbslot dma1_3; + struct cbslot dma1_4; + struct cbslot dma1_5; + struct cbslot dma1_6; + struct cbslot dma1_7; + struct cbslot dma1_8; + + struct cbslot dma2_1; + struct cbslot dma2_2; + struct cbslot dma2_3; + struct cbslot dma2_4; + struct cbslot dma2_5; + struct cbslot dma2_6; + struct cbslot dma2_7; + struct cbslot dma2_8; + + // XXX add more callbacks here when needed +} callbacks = {0}; + +static struct cbslot *get_slot_for_periph(void *periph) +{ + struct cbslot *slot = NULL; + // --- USART --- + if (periph == USART1) slot = &callbacks.usart1; + else if (periph == USART2) slot = &callbacks.usart2; + else if (periph == USART3) slot = &callbacks.usart3; +#ifdef USART4 + else if (periph == USART4) slot = &callbacks.usart4; +#endif +#ifdef USART5 + else if (periph == USART5) slot = &callbacks.usart5; +#endif + + // --- DMA1 --- + else if (periph == DMA1_Channel1) slot = &callbacks.dma1_1; + else if (periph == DMA1_Channel2) slot = &callbacks.dma1_2; + else if (periph == DMA1_Channel3) slot = &callbacks.dma1_3; + else if (periph == DMA1_Channel4) slot = &callbacks.dma1_4; + else if (periph == DMA1_Channel5) slot = &callbacks.dma1_5; + else if (periph == DMA1_Channel6) slot = &callbacks.dma1_6; + else if (periph == DMA1_Channel7) slot = &callbacks.dma1_7; +#ifdef DMA1_Channel8 + else if (periph == DMA1_Channel7) slot = &callbacks.dma1_8; +#endif + + // --- DMA2 --- +#ifdef DMA2 + else if (periph == DMA2_Channel1) slot = &callbacks.dma2_1; + else if (periph == DMA2_Channel2) slot = &callbacks.dma2_2; + else if (periph == DMA2_Channel3) slot = &callbacks.dma2_3; + else if (periph == DMA2_Channel4) slot = &callbacks.dma2_4; + else if (periph == DMA2_Channel5) slot = &callbacks.dma2_5; + #ifdef DMA2_Channel6 + else if (periph == DMA2_Channel6) slot = &callbacks.dma2_6; + #endif + #ifdef DMA2_Channel7 + else if (periph == DMA2_Channel7) slot = &callbacks.dma2_7; + #endif + #ifdef DMA2_Channel8 + else if (periph == DMA2_Channel7) slot = &callbacks.dma2_8; + #endif +#endif + else { + trap("No IRQ cb slot for periph 0x%p", periph); + } + + return slot; +} + +void irqd_attach(void *periph, IrqCallback callback, void *arg) +{ + struct cbslot *slot = get_slot_for_periph(periph); + slot->callback = callback; + slot->arg = arg; +} + +void irqd_detach(void *periph, IrqCallback callback) +{ + struct cbslot *slot = get_slot_for_periph(periph); + if (slot->callback == callback) { + slot->callback = NULL; + slot->arg = NULL; + } +} + +#define CALL_IRQ_HANDLER(slot) do { if (slot.callback) slot.callback(slot.arg); } while (0) + +void USART1_IRQHandler(void) +{ + CALL_IRQ_HANDLER(callbacks.usart1); +} + +void USART2_IRQHandler(void) +{ + CALL_IRQ_HANDLER(callbacks.usart2); +} + +#if 0 +static bool usart_check_irq(USART_TypeDef *USARTx) +{ + uint32_t isrflags = USARTx->ISR; + uint32_t cr1its = USARTx->CR1; + uint32_t cr2its = USARTx->CR2; + uint32_t cr3its = USARTx->CR3; + + if ((cr1its & USART_CR1_RTOIE) && (isrflags & USART_ISR_RTOF)) return true; + if ((cr1its & USART_CR1_RXNEIE) && (isrflags & USART_ISR_RXNE)) return true; + if ((cr1its & USART_CR1_TCIE) && (isrflags & USART_ISR_TC)) return true; + if ((cr1its & USART_CR1_TXEIE) && (isrflags & USART_ISR_TXE)) return true; + if ((cr3its & USART_CR3_EIE) && (isrflags & (USART_ISR_PE | USART_ISR_FE | USART_ISR_ORE | USART_ISR_NE))) return true; + + if ((cr1its & USART_CR1_IDLEIE) && (isrflags & USART_ISR_IDLE)) return true; + if ((cr1its & USART_CR1_PEIE) && (isrflags & USART_ISR_PE)) return true; + if ((cr1its & USART_CR1_CMIE) && (isrflags & USART_ISR_CMF)) return true; + if ((cr1its & USART_CR1_EOBIE) && (isrflags & USART_ISR_EOBF)) return true; + if ((cr2its & USART_CR2_LBDIE) && (isrflags & USART_ISR_LBDF)) return true; + if ((cr3its & USART_CR3_CTSIE) && (isrflags & USART_ISR_CTS)) return true; + if ((cr3its & USART_CR3_WUFIE) && (isrflags & USART_ISR_WUF)) return true; + + return false; +} +#endif + +void USART3_4_IRQHandler(void) +{ + // we won't check the flags here, both can be pending and it's better to let the handler deal with it + CALL_IRQ_HANDLER(callbacks.usart3); + CALL_IRQ_HANDLER(callbacks.usart4); +} + +void DMA1_Channel1_IRQHandler(void) +{ + CALL_IRQ_HANDLER(callbacks.dma1_1); +} + +void DMA1_Channel2_3_IRQHandler(void) +{ + if (LL_DMA_IsActiveFlag_GI2(DMA1)) CALL_IRQ_HANDLER(callbacks.dma1_2); + if (LL_DMA_IsActiveFlag_GI3(DMA1)) CALL_IRQ_HANDLER(callbacks.dma1_3); +} + +void DMA1_Channel4_5_6_7_IRQHandler(void) +{ + if (LL_DMA_IsActiveFlag_GI4(DMA1)) CALL_IRQ_HANDLER(callbacks.dma1_4); + if (LL_DMA_IsActiveFlag_GI5(DMA1)) CALL_IRQ_HANDLER(callbacks.dma1_5); + if (LL_DMA_IsActiveFlag_GI6(DMA1)) CALL_IRQ_HANDLER(callbacks.dma1_6); + if (LL_DMA_IsActiveFlag_GI7(DMA1)) CALL_IRQ_HANDLER(callbacks.dma1_7); +} + +#if 0 +void WWDG_IRQHandler(void) +{ + // +} + +void PVD_VDDIO2_IRQHandler(void) +{ + // +} + +void RTC_IRQHandler(void) +{ + // +} + +void FLASH_IRQHandler(void) +{ + // +} + +void RCC_CRS_IRQHandler(void) +{ + // +} + +void EXTI0_1_IRQHandler(void) +{ + // +} + +void EXTI2_3_IRQHandler(void) +{ + // +} + +void EXTI4_15_IRQHandler(void) +{ + // +} + +void TSC_IRQHandler(void) +{ + // +} + +void ADC1_COMP_IRQHandler(void) +{ + // +} + +void TIM1_BRK_UP_TRG_COM_IRQHandler(void) +{ + // +} + +void TIM1_CC_IRQHandler(void) +{ + // +} + +void TIM2_IRQHandler(void) +{ + // +} + +void TIM3_IRQHandler(void) +{ + // +} + +// not on F072 +void TIM4_IRQHandler(void) +{ + // +} + +// not on F072 +void TIM5_IRQHandler(void) +{ + // +} + +void TIM6_DAC_IRQHandler(void) +{ + // +} + +void TIM7_IRQHandler(void) +{ + // +} + +void TIM8_IRQHandler(void) +{ + // +} + +void TIM9_IRQHandler(void) +{ + // +} + +void TIM10_IRQHandler(void) +{ + // +} + +void TIM11_IRQHandler(void) +{ + // +} + +void TIM12_IRQHandler(void) +{ + // +} + +void TIM13_IRQHandler(void) +{ + // +} + +void TIM14_IRQHandler(void) +{ + // +} + +void TIM15_IRQHandler(void) +{ + // +} + +void TIM16_IRQHandler(void) +{ + // +} + +void TIM17_IRQHandler(void) +{ + // +} + +void CEC_CAN_IRQHandler(void) +{ + // +} + +// USB is handled by the USB driver + +//void USB_IRQHandler(void) +//{ +// // +//} +#endif diff --git a/platform/irq_dispatcher.h b/platform/irq_dispatcher.h new file mode 100644 index 0000000..76cb731 --- /dev/null +++ b/platform/irq_dispatcher.h @@ -0,0 +1,39 @@ +// +// Created by MightyPork on 2018/01/14. +// + +#ifndef GEX_F072_IRQ_DISPATCHER_H +#define GEX_F072_IRQ_DISPATCHER_H + +/** + * Initialize the interrupt dispatcher + */ +void irqd_init(void); + +/** Typedef for a IRQ callback run by the dispatcher */ +typedef void (*IrqCallback)(void*); + +/** + * Attach a callback to a IRQ handler. + * Pass NULL to remove the handler. + * + * NOTE: The handler is responsible for clearing any interrupt status flags. + * NOTE: It is not guaranteed that the particular peripheral caused the interrupt when + * the function is called; some interrupt vectors are shared. Make sure to check the flags. + * + * @param periph - peripheral we're attaching to + * @param callback - callback to fire on IRQ + * @param data - data passed to the callback (user context) + */ +void irqd_attach(void *periph, IrqCallback callback, void *data); + + +/** + * Remove a callback + * + * @param periph - peripheral we're attaching to + * @param callback - callback to remove, if it doesn't match, do nothing + */ +void irqd_detach(void *periph, IrqCallback callback); + +#endif //GEX_F072_IRQ_DISPATCHER_H diff --git a/platform/plat_init.c b/platform/plat_init.c index d6b5034..743babd 100644 --- a/platform/plat_init.c +++ b/platform/plat_init.c @@ -11,6 +11,7 @@ #include "lock_jumper.h" #include "status_led.h" #include "debug_uart.h" +#include "irq_dispatcher.h" void plat_init(void) { @@ -30,4 +31,5 @@ void plat_init(void) settings_load(); // XXX maybe this should be moved to the main task comm_init(); + irqd_init(); } diff --git a/stm32_assert.c b/stm32_assert.c index 6cfcdff..be139da 100644 --- a/stm32_assert.c +++ b/stm32_assert.c @@ -1,29 +1,15 @@ #include "platform.h" #include "platform/status_led.h" -/** - * Abort at file, line with a custom tag (eg. ASSERT FAILED) - * @param msg - tag message - * @param filename - file - * @param line - line - */ -void __attribute__((noreturn)) abort_msg(const char *msg, const char *filename, uint32_t line) +void _abort_errlight(void) { - dbg("\r\n\033[31m%s:\033[m %s:%"PRIu32, msg, filename, line); - vPortEnterCritical(); Indicator_Effect(STATUS_FAULT); - while(1); } -/** - * Warn at file, line with a custom tag (eg. ASSERT FAILED) - * @param msg - tag message - * @param filename - file - * @param line - line - */ -void warn_msg(const char *msg, const char *filename, uint32_t line) +void __attribute__((noreturn)) _abort_do(void) { - dbg("\r\n\033[33m%s:\033[m %s:%"PRIu32, msg, filename, line); + vPortEnterCritical(); + while(1); } /** @@ -32,7 +18,7 @@ void warn_msg(const char *msg, const char *filename, uint32_t line) * @param file: pointer to the source file name * @param line: assert_param error line source number */ -void __attribute__((noreturn)) assert_failed_(const char *file, uint32_t line) +void __attribute__((noreturn)) _assert_failed(const char *file, uint32_t line) { - abort_msg("ASSERT FAILED", file, line); + _abort_msg(file, line, "ASSERT FAILED"); } diff --git a/stm32_assert.h b/stm32_assert.h index 231fab1..f3c9e09 100644 --- a/stm32_assert.h +++ b/stm32_assert.h @@ -6,30 +6,45 @@ #define STM32_ASSERT_H #include +#include "debug.h" -void __attribute__((noreturn)) abort_msg(const char *msg, const char *filename, uint32_t line); -void warn_msg(const char *msg, const char *filename, uint32_t line); -void __attribute__((noreturn)) assert_failed_(const char *file, uint32_t line); +void _abort_errlight(void); +void __attribute__((noreturn)) _assert_failed(const char *file, uint32_t line); +void __attribute__((noreturn)) _abort_do(void); + +#define _abort_msg(file, line, format, ...) do { \ + _abort_errlight(); \ + dbg("\r\n\033[31m" format ":\033[m %s:%d", ##__VA_ARGS__, file, (int)line); \ + _abort_do(); \ +} while (0) + +#define _warn_msg(file, line, format, ...) do { \ + dbg("\r\n\033[33m" format ":\033[m %s:%d", ##__VA_ARGS__, file, (int)line); \ +} while (0) #if USE_FULL_ASSERT #if ASSERT_FILENAMES // With the filename enabled. - #define trap(msg) abort_msg(msg, __BASE_FILE__, __LINE__) - #define assert_param(expression) do { if (!(expression)) assert_failed_(__BASE_FILE__, __LINE__); } while(0) - #define assert_warn(expression, msg) do { if (!(expression)) warn_msg(msg, __BASE_FILE__, __LINE__); } while(0) - #define _Error_Handler(file, line) assert_failed_(__BASE_FILE__, __LINE__) + #define trap(msg, ...) _abort_msg(__BASE_FILE__, __LINE__, msg, ##__VA_ARGS__) + #define warn(msg, ...) _warn_msg(__BASE_FILE__, __LINE__, msg, ##__VA_ARGS__) + #define assert_param(expression) do { if (!(expression)) _assert_failed(__BASE_FILE__, __LINE__); } while(0) + #define assert_warn(expression, msg, ...) do { if (!(expression)) _warn_msg(__BASE_FILE__, __LINE__, msg, ##__VA_ARGS__); } while(0) + #define _Error_Handler(file, line) _assert_failed(__BASE_FILE__, __LINE__) #else // Filename disabled to save code size. - #define trap(msg) abort_msg(msg, "??", __LINE__) - #define assert_param(expression) do { if (!(expression)) assert_failed_("??", __LINE__); } while(0) - #define assert_warn(expression, msg) do { if (!(expression)) warn_msg(msg, "??", __LINE__); } while(0) - #define _Error_Handler(file, line) assert_failed_("??", __LINE__) + #define trap(msg, ...) _abort_msg("??", __LINE__, msg, ##__VA_ARGS__) + #define warn(msg, ...) _warn_msg("??", __LINE__, msg, ##__VA_ARGS__) + #define assert_param(expression) do { if (!(expression)) _assert_failed("??", __LINE__); } while(0) + #define assert_warn(expression, msg, ...) do { if (!(expression)) _warn_msg("??", __LINE__, msg, ##__VA_ARGS__); } while(0) + #define _Error_Handler(file, line) _assert_failed("??", __LINE__) #endif #else // This is after everything is well tested, to cut some flash and make code faster by removing checks - #define trap(msg) do {} while(1) + // must take care to evaluate the expressions regardless in case they have side effects. + #define trap(msg, ...) do {} while(1) + #define warn(msg, ...) #define assert_param(expression) do { (void)(expression); } while(0) - #define assert_warn(expression, msg) do { (void)(expression); } while(0) + #define assert_warn(expression, msg, ...) do { (void)(expression); } while(0) #define _Error_Handler(file, line) do {} while(1) #endif diff --git a/units/usart/_dmas.c b/units/usart/_dmas.c new file mode 100644 index 0000000..c0622de --- /dev/null +++ b/units/usart/_dmas.c @@ -0,0 +1,255 @@ +// +// Created by MightyPork on 2018/01/14. +// +#include +#include +#include +#include "platform.h" +#include "unit_base.h" + +#define UUSART_INTERNAL +#include "_internal.h" + +static void UUSART_DMA_RxHandler(void *arg); +static void UUSART_DMA_TxHandler(void *arg); + +error_t UUSART_ClaimDMAs(Unit *unit) +{ + error_t rv; + assert_param(unit); + struct priv *priv = unit->data; + assert_param(priv); + + priv->dma = DMA1; + + switch (priv->periph_num) { + /* USART1 */ + case 1: + // TX + rv = rsc_claim(unit, R_DMA1_2); + if (rv == E_SUCCESS) { + LL_SYSCFG_SetRemapDMA_USART(LL_SYSCFG_USART1TX_RMP_DMA1CH2); + priv->dma_tx = DMA1_Channel2; + priv->dma_tx_chnum = 2; + } else { + // try the remap + TRY(rsc_claim(unit, R_DMA1_4)); + LL_SYSCFG_SetRemapDMA_USART(LL_SYSCFG_USART1TX_RMP_DMA1CH4); + priv->dma_tx = DMA1_Channel4; + priv->dma_tx_chnum = 4; + } + + // RX + rv = rsc_claim(unit, R_DMA1_3); + if (rv == E_SUCCESS) { + LL_SYSCFG_SetRemapDMA_USART(LL_SYSCFG_USART1RX_RMP_DMA1CH3); + priv->dma_rx = DMA1_Channel3; + priv->dma_rx_chnum = 3; + } else { + // try the remap + TRY(rsc_claim(unit, R_DMA1_5)); + LL_SYSCFG_SetRemapDMA_USART(LL_SYSCFG_USART1RX_RMP_DMA1CH5); + priv->dma_rx = DMA1_Channel5; + priv->dma_rx_chnum = 5; + } + break; + + /* USART2 */ + case 2: + // RX,TX + rv = rsc_claim_range(unit, R_DMA1_4, R_DMA1_5); + if (rv == E_SUCCESS) { + LL_SYSCFG_SetRemapDMA_USART(LL_SYSCFG_USART2_RMP_DMA1CH54); + priv->dma_tx = DMA1_Channel4; + priv->dma_rx = DMA1_Channel5; + priv->dma_tx_chnum = 4; + priv->dma_rx_chnum = 5; + } else { + // try the remap + TRY(rsc_claim_range(unit, R_DMA1_6, R_DMA1_7)); + LL_SYSCFG_SetRemapDMA_USART(LL_SYSCFG_USART2_RMP_DMA1CH67); + priv->dma_tx = DMA1_Channel7; + priv->dma_rx = DMA1_Channel6; + priv->dma_tx_chnum = 7; + priv->dma_rx_chnum = 6; + } + break; + + /* USART3 */ + case 3: + // RX,TX + rv = rsc_claim_range(unit, R_DMA1_6, R_DMA1_7); + if (rv == E_SUCCESS) { + LL_SYSCFG_SetRemapDMA_USART(LL_SYSCFG_USART3_RMP_DMA1CH67); + priv->dma_tx = DMA1_Channel7; + priv->dma_rx = DMA1_Channel6; + priv->dma_tx_chnum = 7; + priv->dma_rx_chnum = 6; + } else { + // try the remap + TRY(rsc_claim_range(unit, R_DMA1_2, R_DMA1_3)); + LL_SYSCFG_SetRemapDMA_USART(LL_SYSCFG_USART3_RMP_DMA1CH32); + priv->dma_tx = DMA1_Channel2; + priv->dma_rx = DMA1_Channel3; + priv->dma_tx_chnum = 2; + priv->dma_rx_chnum = 3; + } + break; + + /* USART4 */ + case 4: + // RX,TX + TRY(rsc_claim_range(unit, R_DMA1_6, R_DMA1_7)); + priv->dma_tx = DMA1_Channel7; + priv->dma_rx = DMA1_Channel6; + priv->dma_tx_chnum = 7; + priv->dma_rx_chnum = 6; + break; + + default: + trap("Missing DMA mapping for USART%d", (int)priv->periph_num); + } + + dbg("USART %d - selected DMA ch Tx(%d), Rx(%d)", priv->periph_num, priv->dma_tx_chnum, priv->dma_rx_chnum); + + return E_SUCCESS; +} + +error_t UUSART_SetupDMAs(Unit *unit) +{ + assert_param(unit); + struct priv *priv = unit->data; + assert_param(priv); + + priv->rx_buffer = malloc_ck(UUSART_RXBUF_LEN); + if (NULL == priv->rx_buffer) return E_OUT_OF_MEM; + + priv->tx_buffer = malloc_ck(UUSART_TXBUF_LEN); + if (NULL == priv->tx_buffer) return E_OUT_OF_MEM; + + priv->rx_buf_readpos = 0; + + LL_DMA_InitTypeDef init; + + // Transmit buffer + { + LL_DMA_StructInit(&init); + init.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + init.Mode = LL_DMA_MODE_CIRCULAR; + + init.PeriphOrM2MSrcAddress = (uint32_t) &priv->periph->TDR; + init.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_BYTE; + init.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + + init.MemoryOrM2MDstAddress = (uint32_t) priv->tx_buffer; + init.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_BYTE; + init.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + + assert_param(SUCCESS == LL_DMA_Init(priv->dma, priv->dma_tx_chnum, &init)); + + irqd_attach(priv->dma_tx, UUSART_DMA_TxHandler, unit); + // Interrupt on transfer complete + LL_DMA_EnableIT_TC(priv->dma, priv->dma_tx_chnum); + } + + // Receive buffer + { + LL_DMA_StructInit(&init); + init.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY; + + init.Mode = LL_DMA_MODE_CIRCULAR; + init.NbData = UUSART_RXBUF_LEN; + + init.PeriphOrM2MSrcAddress = (uint32_t) &priv->periph->RDR; + init.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_BYTE; + init.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + + init.MemoryOrM2MDstAddress = (uint32_t) priv->rx_buffer; + init.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_BYTE; + init.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + + assert_param(SUCCESS == LL_DMA_Init(priv->dma, priv->dma_rx_chnum, &init)); + + irqd_attach(priv->dma_rx, UUSART_DMA_RxHandler, unit); + // Interrupt on transfer 1/2 and complete + // We will capture the first and second half and send it while the other half is being filled. + LL_DMA_EnableIT_HT(priv->dma, priv->dma_rx_chnum); + LL_DMA_EnableIT_TC(priv->dma, priv->dma_rx_chnum); + } + + LL_DMA_EnableChannel(priv->dma, priv->dma_rx_chnum); + LL_DMA_EnableChannel(priv->dma, priv->dma_tx_chnum); + + // TODO also set up usart timeout interrupt that grabs whatever is in the DMA buffer and sends it + return E_SUCCESS; +} + +static void UUSART_DMA_RxHandler(void *arg) +{ + Unit *unit = arg; + assert_param(unit); + struct priv *priv = unit->data; + assert_param(priv); + + uint32_t isrsnapshot = priv->dma->ISR; + + if (LL_DMA_IsActiveFlag_G(isrsnapshot, priv->dma_rx_chnum)) { + bool tc = LL_DMA_IsActiveFlag_TC(isrsnapshot, priv->dma_rx_chnum); + bool ht = LL_DMA_IsActiveFlag_HT(isrsnapshot, priv->dma_rx_chnum); + + + uint16_t end = (uint16_t) (ht ? UUSART_RXBUF_LEN / 2 : UUSART_RXBUF_LEN); + + uint16_t toRead = (uint16_t) (end - priv->rx_buf_readpos); + + PUTS(">"); + PUTSN((char *) priv->rx_buffer+priv->rx_buf_readpos, toRead); + PUTS("<\r\n"); + + // Prepare position for next read + if (ht) priv->rx_buf_readpos = (uint16_t) (end); + else priv->rx_buf_readpos = 0; + + + if (ht) LL_DMA_ClearFlag_HT(priv->dma, priv->dma_rx_chnum); + if (tc) LL_DMA_ClearFlag_TC(priv->dma, priv->dma_rx_chnum); + if (LL_DMA_IsActiveFlag_TE(isrsnapshot, priv->dma_rx_chnum)) { + dbg("Rx TE"); // this shouldn't happen + LL_DMA_ClearFlag_TE(priv->dma, priv->dma_rx_chnum); + } + } +} + +static void UUSART_DMA_TxHandler(void *arg) +{ + Unit *unit = arg; + assert_param(unit); + struct priv *priv = unit->data; + assert_param(priv); + + uint32_t isrsnapshot = priv->dma->ISR; + if (LL_DMA_IsActiveFlag_G(isrsnapshot, priv->dma_tx_chnum)) { + if (LL_DMA_IsActiveFlag_TC(isrsnapshot, priv->dma_tx_chnum)) { + dbg("Tx TC"); + } + + LL_DMA_ClearFlags(priv->dma, priv->dma_tx_chnum); + } +} + + +void UUSART_DeInitDMAs(Unit *unit) +{ + assert_param(unit); + struct priv *priv = unit->data; + assert_param(priv); + + irqd_detach(priv->dma_tx, UUSART_DMA_RxHandler); + irqd_detach(priv->dma_rx, UUSART_DMA_TxHandler); + + LL_DMA_DeInit(priv->dma, priv->dma_rx_chnum); + LL_DMA_DeInit(priv->dma, priv->dma_tx_chnum); + + free_ck(priv->rx_buffer); + free_ck(priv->tx_buffer); +} diff --git a/units/usart/_init.c b/units/usart/_init.c new file mode 100644 index 0000000..2679b19 --- /dev/null +++ b/units/usart/_init.c @@ -0,0 +1,343 @@ +// +// Created by MightyPork on 2018/01/14. +// +#include "platform.h" +#include "unit_base.h" + +#define UUSART_INTERNAL +#include "_internal.h" + +extern error_t UUSART_ClaimDMAs(Unit *unit); +extern error_t UUSART_SetupDMAs(Unit *unit); +extern void UUSART_DeInitDMAs(Unit *unit); + +/** Allocate data structure and set defaults */ +error_t UUSART_preInit(Unit *unit) +{ + struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv)); + if (priv == NULL) return E_OUT_OF_MEM; + + // some defaults + priv->periph_num = 1; + priv->remap = 0; + + priv->baudrate = 115200; + priv->parity = 0; //!< 0-none, 1-odd, 2-even + priv->stopbits = 1; //!< 0-half, 1-one, 2-1.5, 3-two + priv->direction = 3; // RXTX + + priv->hw_flow_control = false; + priv->clock_output = false; + priv->cpol = 0; + priv->cpha = 0; + priv->lsb_first = true; // LSB first is default for UART + priv->width = 8; + + priv->data_inv = false; + priv->rx_inv = false; + priv->tx_inv = false; + + priv->de_output = false; + priv->de_polarity = 1; // active high + // this should equal to a half-byte length when oversampling by 16 is used (default) + priv->de_assert_time = 8; + priv->de_clear_time = 8; + + priv->rx_buffer = NULL; + priv->tx_buffer = NULL; + + return E_SUCCESS; +} + +/** Claim the peripheral and assign priv->periph */ +static inline error_t UUSART_claimPeriph(Unit *unit) +{ + struct priv *priv = unit->data; + + if (!(priv->periph_num >= 1 && priv->periph_num <= 5)) { + dbg("!! Bad USART periph"); + return E_BAD_CONFIG; + } + + // assign and claim the peripheral + if (priv->periph_num == 1) { + TRY(rsc_claim(unit, R_USART1)); + priv->periph = USART1; + } + else if (priv->periph_num == 2) { + TRY(rsc_claim(unit, R_USART2)); + priv->periph = USART2; + } + else if (priv->periph_num == 3) { + TRY(rsc_claim(unit, R_USART3)); + priv->periph = USART3; + } +#if defined(USART4) + else if (priv->periph_num == 4) { + TRY(rsc_claim(unit, R_USART4)); + priv->periph = USART4; + } +#endif +#if defined(USART5) + else if (priv->periph_num == 5) { + TRY(rsc_claim(unit, R_USART5)); + priv->periph = USART5; + } +#endif + else return E_BAD_CONFIG; + + TRY(UUSART_ClaimDMAs(unit)); + + return E_SUCCESS; +} + +/** Claim and configure GPIOs used */ +static inline error_t UUSART_configPins(Unit *unit) +{ + struct priv *priv = unit->data; + // This is written for F072, other platforms will need adjustments + + // Configure UART pins (AF) + +#define want_ck_pin(priv) ((priv)->clock_output) +#define want_tx_pin(priv) (bool)((priv)->direction & 2) +#define want_rx_pin(priv) (bool)((priv)->direction & 1) +#define want_cts_pin(priv) ((priv)->hw_flow_control==2 || (priv)->hw_flow_control==3) +#define want_rts_pin(priv) ((priv)->de_output || (priv)->hw_flow_control==1 || (priv)->hw_flow_control==3) + + /* List of required pins based on the user config */ + bool pins_wanted[5] = { + want_ck_pin(priv), + want_tx_pin(priv), + want_rx_pin(priv), + want_cts_pin(priv), + want_rts_pin(priv) + }; + +#if GEX_PLAT_F072_DISCOVERY + + const struct PinAF *mappings = NULL; + + // TODO adjust this, possibly remove / split to individual pin config for .. + // the final board + + const struct PinAF mapping_1_0[5] = { + {'A', 8, LL_GPIO_AF_1}, // CK + {'A', 9, LL_GPIO_AF_1}, // TX + {'A', 10, LL_GPIO_AF_1}, // RX + {'A', 11, LL_GPIO_AF_1}, // CTS - collides with USB + {'A', 12, LL_GPIO_AF_1}, // RTS - collides with USB + }; + + const struct PinAF mapping_1_1[5] = { + {'A', 8, LL_GPIO_AF_1}, // CK* + {'B', 6, LL_GPIO_AF_1}, // TX + {'B', 7, LL_GPIO_AF_1}, // RX + {'A', 11, LL_GPIO_AF_1}, // CTS* - collides with USB + {'A', 12, LL_GPIO_AF_1}, // RTS* - collides with USB + }; + + const struct PinAF mapping_2_0[5] = { + {'A', 4, LL_GPIO_AF_1}, // CK + {'A', 2, LL_GPIO_AF_1}, // TX + {'A', 3, LL_GPIO_AF_1}, // RX + {'A', 0, LL_GPIO_AF_1}, // CTS + {'A', 1, LL_GPIO_AF_1}, // RTS + }; + + const struct PinAF mapping_2_1[5] = { + {'A', 4, LL_GPIO_AF_1}, // CK* + {'A', 14, LL_GPIO_AF_1}, // TX + {'A', 15, LL_GPIO_AF_1}, // RX + {'A', 0, LL_GPIO_AF_1}, // CTS* + {'A', 1, LL_GPIO_AF_1}, // RTS* + }; + + const struct PinAF mapping_3_0[5] = { + {'B', 12, LL_GPIO_AF_4}, // CK + {'B', 10, LL_GPIO_AF_4}, // TX + {'B', 11, LL_GPIO_AF_4}, // RX + {'B', 13, LL_GPIO_AF_4}, // CTS + {'B', 14, LL_GPIO_AF_4}, // RTS + }; + + const struct PinAF mapping_4_0[5] = { + {'C', 12, LL_GPIO_AF_0}, // CK + {'A', 0, LL_GPIO_AF_4}, // TX + {'A', 1, LL_GPIO_AF_4}, // RX + {'B', 7, LL_GPIO_AF_4}, // CTS + {'A', 15, LL_GPIO_AF_4}, // RTS + }; + + const struct PinAF mapping_4_1[5] = { + {'C', 12, LL_GPIO_AF_0}, // CK* + {'C', 10, LL_GPIO_AF_0}, // TX + {'C', 11, LL_GPIO_AF_0}, // RX + {'B', 7, LL_GPIO_AF_4}, // CTS* + {'A', 15, LL_GPIO_AF_4}, // RTS* + }; + + if (priv->periph_num == 1) { + // USART1 + if (priv->remap == 0) mappings = &mapping_1_0[0]; + else if (priv->remap == 1) mappings = &mapping_1_1[0]; + else return E_BAD_CONFIG; + } + else if (priv->periph_num == 2) { + // USART2 + if (priv->remap == 0) mappings = &mapping_2_0[0]; + else if (priv->remap == 1) mappings = &mapping_2_1[0]; + else return E_BAD_CONFIG; + } + else if (priv->periph_num == 3) { + // USART3 + if (priv->remap == 0) mappings = &mapping_3_0[0]; + else return E_BAD_CONFIG; + } + else if (priv->periph_num == 4) { + // USART3 + if (priv->remap == 0) mappings = &mapping_4_0[0]; + else if (priv->remap == 1) mappings = &mapping_4_1[0]; + else return E_BAD_CONFIG; + } + else return E_BAD_CONFIG; + + // Apply mappings based on the 'wanted' table + for (int i = 0; i < 5; i++) { + if (pins_wanted[i]) { + if (mappings[i].port == 0) return E_BAD_CONFIG; + TRY(rsc_claim_pin(unit, mappings[i].port, mappings[i].pin)); + hw_configure_gpio_af(mappings[i].port, mappings[i].pin, mappings[i].af); + } + } + +#elif GEX_PLAT_F103_BLUEPILL + #error "NO IMPL" +#elif GEX_PLAT_F303_DISCOVERY + #error "NO IMPL" +#elif GEX_PLAT_F407_DISCOVERY + #error "NO IMPL" +#else + #error "BAD PLATFORM!" +#endif + + return E_SUCCESS; +} + +/** Finalize unit set-up */ +error_t UUSART_init(Unit *unit) +{ + struct priv *priv = unit->data; + + TRY(UUSART_claimPeriph(unit)); + TRY(UUSART_configPins(unit)); + + // --- Configure the peripheral --- + + // Enable clock for the peripheral used + hw_periph_clock_enable(priv->periph); + + LL_USART_Disable(priv->periph); + { + LL_USART_DeInit(priv->periph); + LL_USART_SetBaudRate(priv->periph, PLAT_APB1_HZ, LL_USART_OVERSAMPLING_16, priv->baudrate); + + LL_USART_SetParity(priv->periph, + priv->parity == 0 ? LL_USART_PARITY_NONE : + priv->parity == 1 ? LL_USART_PARITY_ODD + : LL_USART_PARITY_EVEN); + + LL_USART_SetStopBitsLength(priv->periph, + priv->stopbits == 0 ? LL_USART_STOPBITS_0_5 : + priv->stopbits == 1 ? LL_USART_STOPBITS_1 : + priv->stopbits == 2 ? LL_USART_STOPBITS_1_5 + : LL_USART_STOPBITS_2); + + LL_USART_SetTransferDirection(priv->periph, + priv->direction == 1 ? LL_USART_DIRECTION_RX : + priv->direction == 2 ? LL_USART_DIRECTION_TX + : LL_USART_DIRECTION_TX_RX); + + LL_USART_SetHWFlowCtrl(priv->periph, + priv->hw_flow_control == 0 ? LL_USART_HWCONTROL_NONE : + priv->hw_flow_control == 1 ? LL_USART_HWCONTROL_RTS : + priv->hw_flow_control == 2 ? LL_USART_HWCONTROL_CTS + : LL_USART_HWCONTROL_RTS_CTS); + + LL_USART_ConfigClock(priv->periph, + priv->cpha ? LL_USART_PHASE_2EDGE : LL_USART_PHASE_1EDGE, + priv->cpol ? LL_USART_POLARITY_HIGH : LL_USART_POLARITY_LOW, + true); // clock on last bit - TODO configurable? + + if (priv->clock_output) + LL_USART_EnableSCLKOutput(priv->periph); + else + LL_USART_DisableSCLKOutput(priv->periph); + + LL_USART_SetTransferBitOrder(priv->periph, + priv->lsb_first ? LL_USART_BITORDER_LSBFIRST + : LL_USART_BITORDER_MSBFIRST); + + LL_USART_SetDataWidth(priv->periph, + priv->width == 7 ? LL_USART_DATAWIDTH_7B : + priv->width == 8 ? LL_USART_DATAWIDTH_8B + : LL_USART_DATAWIDTH_9B); + + LL_USART_SetBinaryDataLogic(priv->periph, + priv->data_inv ? LL_USART_BINARY_LOGIC_NEGATIVE + : LL_USART_BINARY_LOGIC_POSITIVE); + + LL_USART_SetRXPinLevel(priv->periph, priv->rx_inv ? LL_USART_RXPIN_LEVEL_INVERTED + : LL_USART_RXPIN_LEVEL_STANDARD); + + LL_USART_SetTXPinLevel(priv->periph, priv->tx_inv ? LL_USART_TXPIN_LEVEL_INVERTED + : LL_USART_TXPIN_LEVEL_STANDARD); + + if (priv->de_output) + LL_USART_EnableDEMode(priv->periph); + else + LL_USART_DisableDEMode(priv->periph); + + LL_USART_SetDESignalPolarity(priv->periph, + priv->de_polarity ? LL_USART_DE_POLARITY_HIGH + : LL_USART_DE_POLARITY_LOW); + + LL_USART_SetDEAssertionTime(priv->periph, priv->de_assert_time); + LL_USART_SetDEDeassertionTime(priv->periph, priv->de_clear_time); + + // Prepare for DMA + LL_USART_ClearFlag_TC(priv->periph); + LL_USART_EnableDMAReq_RX(priv->periph); + LL_USART_EnableDMAReq_TX(priv->periph); + } + LL_USART_Enable(priv->periph); + + // modifies some usart registers that can't be modified when enabled + TRY(UUSART_SetupDMAs(unit)); + + return E_SUCCESS; +} + +/** Tear down the unit */ +void UUSART_deInit(Unit *unit) +{ + struct priv *priv = unit->data; + + // de-init the pins & peripheral only if inited correctly + if (unit->status == E_SUCCESS) { + assert_param(priv->periph); + LL_USART_DeInit(priv->periph); + + // Disable clock + hw_periph_clock_disable(priv->periph); + + UUSART_DeInitDMAs(unit); + } + + // Release all resources + rsc_teardown(unit); + + // Free memory + free_ck(unit->data); + unit->data = NULL; +} diff --git a/units/usart/_internal.h b/units/usart/_internal.h new file mode 100644 index 0000000..39dfd02 --- /dev/null +++ b/units/usart/_internal.h @@ -0,0 +1,56 @@ +// +// Created by MightyPork on 2018/01/14. +// + +#ifndef GEX_F072_UUSART_INTERNAL_H +#define GEX_F072_UUSART_INTERNAL_H + +#ifndef UUSART_INTERNAL +#error "Bad include" +#endif + +#include "platform.h" + +#define UUSART_RXBUF_LEN 128 +#define UUSART_TXBUF_LEN 128 + +/** Private data structure */ +struct priv { + uint8_t periph_num; //!< 1-6 + uint8_t remap; //!< UART remap option + + uint32_t baudrate; //!< baud rate + uint8_t parity; //!< 0-none, 1-odd, 2-even + uint8_t stopbits; //!< 0-half, 1-one, 2-one-and-half, 3-two (halves - 1) + uint8_t direction; //!< 1-RX, 2-TX, 3-RXTX + + uint8_t hw_flow_control; //!< HW flow control 0-none, 1-RTC, 2-CTS, 3-full + bool clock_output; //!< Output serial clock + bool cpol; //!< clock CPOL setting + bool cpha; //!< clock CPHA setting + bool lsb_first; //!< bit order + uint8_t width; //!< word width - 7, 8, 9 (this includes parity) + + bool data_inv; //!< Invert data bytes + bool rx_inv; //!< Invert the RX pin levels + bool tx_inv; //!< Invert the TX pin levels + + bool de_output; //!< Generate the Driver Enable signal for RS485 + bool de_polarity; //!< DE active level + uint8_t de_assert_time; //!< Time to assert the DE signal before transmit + uint8_t de_clear_time; //!< Time to clear the DE signal after transmit + + USART_TypeDef *periph; + + DMA_TypeDef *dma; + DMA_Channel_TypeDef *dma_rx; + DMA_Channel_TypeDef *dma_tx; + uint8_t dma_rx_chnum; + uint8_t dma_tx_chnum; + + uint8_t *rx_buffer; + uint8_t *tx_buffer; + uint16_t rx_buf_readpos; +}; + +#endif //GEX_F072_UUSART_INTERNAL_H diff --git a/units/usart/_settings_bin.c b/units/usart/_settings_bin.c new file mode 100644 index 0000000..dcfe398 --- /dev/null +++ b/units/usart/_settings_bin.c @@ -0,0 +1,74 @@ +// +// Created by MightyPork on 2018/01/14. +// + +#include "platform.h" +#include "unit_base.h" + +#define UUSART_INTERNAL +#include "_internal.h" + +/** Load from a binary buffer stored in Flash */ +void UUSART_loadBinary(Unit *unit, PayloadParser *pp) +{ + struct priv *priv = unit->data; + + uint8_t version = pp_u8(pp); + (void)version; + + priv->periph_num = pp_u8(pp); + priv->remap = pp_u8(pp); + + priv->baudrate = pp_u32(pp); + priv->parity = pp_u8(pp); + priv->stopbits = pp_u8(pp); + priv->direction = pp_u8(pp); + + priv->hw_flow_control = pp_u8(pp); + priv->clock_output = pp_bool(pp); + priv->cpol = pp_bool(pp); + priv->cpha = pp_bool(pp); + priv->lsb_first = pp_bool(pp); + priv->width = pp_u8(pp); + + priv->data_inv = pp_bool(pp); + priv->rx_inv = pp_bool(pp); + priv->tx_inv = pp_bool(pp); + + priv->de_output = pp_bool(pp); + priv->de_polarity = pp_bool(pp); + priv->de_assert_time = pp_u8(pp); + priv->de_clear_time = pp_u8(pp); +} + +/** Write to a binary buffer for storing in Flash */ +void UUSART_writeBinary(Unit *unit, PayloadBuilder *pb) +{ + struct priv *priv = unit->data; + + pb_u8(pb, 0); // version + + pb_u8(pb, priv->periph_num); + pb_u8(pb, priv->remap); + + pb_u32(pb, priv->baudrate); + pb_u8(pb, priv->parity); + pb_u8(pb, priv->stopbits); + pb_u8(pb, priv->direction); + + pb_u8(pb, priv->hw_flow_control); + pb_bool(pb, priv->clock_output); + pb_bool(pb, priv->cpol); + pb_bool(pb, priv->cpha); + pb_bool(pb, priv->lsb_first); + pb_u8(pb, priv->width); + + pb_bool(pb, priv->data_inv); + pb_bool(pb, priv->rx_inv); + pb_bool(pb, priv->tx_inv); + + pb_bool(pb, priv->de_output); + pb_bool(pb, priv->de_polarity); + pb_u8(pb, priv->de_assert_time); + pb_u8(pb, priv->de_clear_time); +} diff --git a/units/usart/_settings_ini.c b/units/usart/_settings_ini.c new file mode 100644 index 0000000..487465c --- /dev/null +++ b/units/usart/_settings_ini.c @@ -0,0 +1,168 @@ +// +// Created by MightyPork on 2018/01/14. +// + +#include "platform.h" +#include "unit_base.h" +#include "avrlibc.h" + +#define UUSART_INTERNAL +#include "_internal.h" + +/** Parse a key-value pair from the INI file */ +error_t UUSART_loadIni(Unit *unit, const char *key, const char *value) +{ + bool suc = true; + struct priv *priv = unit->data; + + if (streq(key, "device")) { + priv->periph_num = (uint8_t) avr_atoi(value); + } + else if (streq(key, "remap")) { + priv->remap = (uint8_t) avr_atoi(value); + } + else if (streq(key, "baud-rate")) { + priv->baudrate = (uint32_t ) avr_atoi(value); + } + else if (streq(key, "parity")) { + priv->parity = (uint8_t) str_parse_3(value, + "NONE", 0, + "ODD", 1, + "EVEN", 2, &suc); + } + else if (streq(key, "stop-bits")) { + priv->stopbits = (uint8_t) str_parse_4(value, + "0.5", 0, + "1", 1, + "1.5", 2, + "2", 3, &suc); + } + else if (streq(key, "direction")) { + priv->direction = (uint8_t) str_parse_3(value, + "RX", 1, + "TX", 2, + "RXTX", 3, &suc); + } + else if (streq(key, "hw-flow-control")) { + priv->hw_flow_control = (uint8_t) str_parse_4(value, + "NONE", 0, + "RTS", 1, + "CTS", 2, + "FULL", 3, &suc); + } + else if (streq(key, "word-width")) { + priv->width = (uint8_t ) avr_atoi(value); + } + else if (streq(key, "first-bit")) { + priv->lsb_first = (bool)str_parse_2(value, "MSB", 0, "LSB", 1, &suc); + } + else if (streq(key, "clock-output")) { + priv->clock_output = str_parse_yn(value, &suc); + } + else if (streq(key, "cpol")) { + priv->cpol = (bool) avr_atoi(value); + } + else if (streq(key, "cpha")) { + priv->cpha = (bool) avr_atoi(value); + } + else if (streq(key, "de-output")) { + priv->de_output = str_parse_yn(value, &suc); + } + else if (streq(key, "de-polarity")) { + priv->de_polarity = (bool) avr_atoi(value); + } + else if (streq(key, "de-assert-time")) { + priv->de_assert_time = (uint8_t) avr_atoi(value); + } + else if (streq(key, "de-clear-time")) { + priv->de_clear_time = (uint8_t) avr_atoi(value); + } + else { + return E_BAD_KEY; + } + + if (!suc) return E_BAD_VALUE; + return E_SUCCESS; +} + +/** Generate INI file section for the unit */ +void UUSART_writeIni(Unit *unit, IniWriter *iw) +{ + struct priv *priv = unit->data; + + iw_comment(iw, "Peripheral number (UARTx 1-4)"); + iw_entry(iw, "device", "%d", (int)priv->periph_num); + + iw_comment(iw, "Pin mappings (TX,RX,CK,CTS,RTS/DE)"); +#if GEX_PLAT_F072_DISCOVERY + iw_comment(iw, " USART1: (0) A9,A10,A8,A11,A12 (1) B6,B7,A8,A11,A12"); + iw_comment(iw, " USART2: (0) A2,A3,A4,A0,A1 (1) A14,A15,A4,A0,A1"); + iw_comment(iw, " USART3: (0) B10,B11,B12,B13,B14"); + iw_comment(iw, " USART4: (0) A0,A1,C12,B7,A15 (1) C10,C11,C12,B7,A15"); +#elif GEX_PLAT_F103_BLUEPILL + #error "NO IMPL" +#elif GEX_PLAT_F303_DISCOVERY + #error "NO IMPL" +#elif GEX_PLAT_F407_DISCOVERY + #error "NO IMPL" +#else + #error "BAD PLATFORM!" +#endif + iw_entry(iw, "remap", "%d", (int)priv->remap); + + iw_cmt_newline(iw); + iw_comment(iw, "Baud rate in bps (eg. 9600, 115200)"); // TODO examples/range + iw_entry(iw, "baud-rate", "%d", (int)priv->baudrate); + + iw_comment(iw, "Parity type (NONE, ODD, EVEN)"); + iw_entry(iw, "parity", "%s", str_3(priv->parity, + 0, "NONE", + 1, "ODD", + 2, "EVEN")); + + iw_comment(iw, "Number of stop bits (0.5, 1, 1.5, 2)"); + iw_entry(iw, "stop-bits", "%s", str_4(priv->stopbits, + 0, "0.5", + 1, "1", + 2, "1.5", + 3, "2")); + + iw_comment(iw, "Bit order (LSB or MSB first)"); + iw_entry(iw, "first-bit", str_2((uint32_t)priv->lsb_first, + 0, "MSB", + 1, "LSB")); + + iw_comment(iw, "Word width (7,8,9) - including parity bit if used"); + iw_entry(iw, "word-width", "%d", (int)priv->width); + + iw_comment(iw, "Enabled lines (RX,TX,RXTX)"); + iw_entry(iw, "direction", str_3(priv->direction, + 1, "RX", + 2, "TX", + 3, "RXTX")); + + iw_comment(iw, "Hardware flow control (NONE, RTS, CTS, FULL)"); + iw_entry(iw, "hw-flow-control", "%s", str_4(priv->hw_flow_control, + 0, "NONE", + 1, "RTS", + 2, "CTS", + 3, "FULL")); + + iw_cmt_newline(iw); + iw_comment(iw, "Generate serial clock (Y,N)"); + iw_entry(iw, "clock-output", str_yn(priv->clock_output)); + iw_comment(iw, "Output clock polarity: 0,1 (clock idle level)"); + iw_entry(iw, "cpol", "%d", (int)priv->cpol); + iw_comment(iw, "Output clock phase: 0,1 (active edge, 0-first, 1-second)"); + iw_entry(iw, "cpha", "%d", (int)priv->cpha); + + iw_cmt_newline(iw); + iw_comment(iw, "Generate RS485 Driver Enable signal (Y,N) - uses RTS pin"); + iw_entry(iw, "de-output", str_yn(priv->de_output)); + iw_comment(iw, "DE active level: 0,1"); + iw_entry(iw, "de-polarity", "%d", (int)(priv->de_polarity)); + iw_comment(iw, "DE assert time (0-31)"); + iw_entry(iw, "de-assert-time", "%d", (int)(priv->de_assert_time)); + iw_comment(iw, "DE clear time (0-31)"); + iw_entry(iw, "de-clear-time", "%d", (int)(priv->de_clear_time)); +} diff --git a/units/usart/unit_usart.c b/units/usart/unit_usart.c index d1404c7..a1c4e5c 100644 --- a/units/usart/unit_usart.c +++ b/units/usart/unit_usart.c @@ -5,586 +5,28 @@ #include "platform.h" #include "comm/messages.h" #include "unit_base.h" -#include "utils/avrlibc.h" #include "unit_usart.h" -// SPI master - -/** Private data structure */ -struct priv { - uint8_t periph_num; //!< 1-6 - uint8_t remap; //!< UART remap option - - uint32_t baudrate; //!< baud rate - uint8_t parity; //!< 0-none, 1-odd, 2-even - uint8_t stopbits; //!< 0-half, 1-one, 2-one-and-half, 3-two (halves - 1) - uint8_t direction; //!< 1-RX, 2-TX, 3-RXTX - - uint8_t hw_flow_control; //!< HW flow control 0-none, 1-RTC, 2-CTS, 3-full - bool clock_output; //!< Output serial clock - bool cpol; //!< clock CPOL setting - bool cpha; //!< clock CPHA setting - bool lsb_first; //!< bit order - uint8_t width; //!< word width - 7, 8, 9 (this includes parity) - - bool data_inv; //!< Invert data bytes - bool rx_inv; //!< Invert the RX pin levels - bool tx_inv; //!< Invert the TX pin levels - - bool de_output; //!< Generate the Driver Enable signal for RS485 - bool de_polarity; //!< DE active level - uint8_t de_assert_time; //!< Time to assert the DE signal before transmit - uint8_t de_clear_time; //!< Time to clear the DE signal after transmit - - USART_TypeDef *periph; -}; +#define UUSART_INTERNAL +#include "_internal.h" /** Allocate data structure and set defaults */ -static error_t UUSART_preInit(Unit *unit) -{ - struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv)); - if (priv == NULL) return E_OUT_OF_MEM; - - // some defaults - priv->periph_num = 1; - priv->remap = 0; - - priv->baudrate = 115200; - priv->parity = 0; //!< 0-none, 1-odd, 2-even - priv->stopbits = 1; //!< 0-half, 1-one, 2-1.5, 3-two - priv->direction = 3; // RXTX - - priv->hw_flow_control = false; - priv->clock_output = false; - priv->cpol = 0; - priv->cpha = 0; - priv->lsb_first = true; // LSB first is default for UART - priv->width = 8; - - priv->data_inv = false; - priv->rx_inv = false; - priv->tx_inv = false; - - priv->de_output = false; - priv->de_polarity = 1; // active high - // this should equal to a half-byte length when oversampling by 16 is used (default) - priv->de_assert_time = 8; - priv->de_clear_time = 8; - - return E_SUCCESS; -} - +extern error_t UUSART_preInit(Unit *unit); // ------------------------------------------------------------------------ - /** Load from a binary buffer stored in Flash */ -static void UUSART_loadBinary(Unit *unit, PayloadParser *pp) -{ - struct priv *priv = unit->data; - - uint8_t version = pp_u8(pp); - (void)version; - - priv->periph_num = pp_u8(pp); - priv->remap = pp_u8(pp); - - priv->baudrate = pp_u32(pp); - priv->parity = pp_u8(pp); - priv->stopbits = pp_u8(pp); - priv->direction = pp_u8(pp); - - priv->hw_flow_control = pp_u8(pp); - priv->clock_output = pp_bool(pp); - priv->cpol = pp_bool(pp); - priv->cpha = pp_bool(pp); - priv->lsb_first = pp_bool(pp); - priv->width = pp_u8(pp); - - priv->data_inv = pp_bool(pp); - priv->rx_inv = pp_bool(pp); - priv->tx_inv = pp_bool(pp); - - priv->de_output = pp_bool(pp); - priv->de_polarity = pp_bool(pp); - priv->de_assert_time = pp_u8(pp); - priv->de_clear_time = pp_u8(pp); -} - +extern void UUSART_loadBinary(Unit *unit, PayloadParser *pp); /** Write to a binary buffer for storing in Flash */ -static void UUSART_writeBinary(Unit *unit, PayloadBuilder *pb) -{ - struct priv *priv = unit->data; - - pb_u8(pb, 0); // version - - pb_u8(pb, priv->periph_num); - pb_u8(pb, priv->remap); - - pb_u32(pb, priv->baudrate); - pb_u8(pb, priv->parity); - pb_u8(pb, priv->stopbits); - pb_u8(pb, priv->direction); - - pb_u8(pb, priv->hw_flow_control); - pb_bool(pb, priv->clock_output); - pb_bool(pb, priv->cpol); - pb_bool(pb, priv->cpha); - pb_bool(pb, priv->lsb_first); - pb_u8(pb, priv->width); - - pb_bool(pb, priv->data_inv); - pb_bool(pb, priv->rx_inv); - pb_bool(pb, priv->tx_inv); - - pb_bool(pb, priv->de_output); - pb_bool(pb, priv->de_polarity); - pb_u8(pb, priv->de_assert_time); - pb_u8(pb, priv->de_clear_time); -} - +extern void UUSART_writeBinary(Unit *unit, PayloadBuilder *pb); // ------------------------------------------------------------------------ - /** Parse a key-value pair from the INI file */ -static error_t UUSART_loadIni(Unit *unit, const char *key, const char *value) -{ - bool suc = true; - struct priv *priv = unit->data; - - if (streq(key, "device")) { - priv->periph_num = (uint8_t) avr_atoi(value); - } - else if (streq(key, "remap")) { - priv->remap = (uint8_t) avr_atoi(value); - } - else if (streq(key, "baud-rate")) { - priv->baudrate = (uint32_t ) avr_atoi(value); - } - else if (streq(key, "parity")) { - priv->parity = (uint8_t) str_parse_3(value, - "NONE", 0, - "ODD", 1, - "EVEN", 2, &suc); - } - else if (streq(key, "stop-bits")) { - priv->stopbits = (uint8_t) str_parse_4(value, - "0.5", 0, - "1", 1, - "1.5", 2, - "2", 3, &suc); - } - else if (streq(key, "direction")) { - priv->direction = (uint8_t) str_parse_3(value, - "RX", 1, - "TX", 2, - "RXTX", 3, &suc); - } - else if (streq(key, "hw-flow-control")) { - priv->hw_flow_control = (uint8_t) str_parse_4(value, - "NONE", 0, - "RTS", 1, - "CTS", 2, - "FULL", 3, &suc); - } - else if (streq(key, "word-width")) { - priv->width = (uint8_t ) avr_atoi(value); - } - else if (streq(key, "first-bit")) { - priv->lsb_first = (bool)str_parse_2(value, "MSB", 0, "LSB", 1, &suc); - } - else if (streq(key, "clock-output")) { - priv->clock_output = str_parse_yn(value, &suc); - } - else if (streq(key, "cpol")) { - priv->cpol = (bool) avr_atoi(value); - } - else if (streq(key, "cpha")) { - priv->cpha = (bool) avr_atoi(value); - } - else if (streq(key, "de-output")) { - priv->de_output = str_parse_yn(value, &suc); - } - else if (streq(key, "de-polarity")) { - priv->de_polarity = (bool) avr_atoi(value); - } - else if (streq(key, "de-assert-time")) { - priv->de_assert_time = (uint8_t) avr_atoi(value); - } - else if (streq(key, "de-clear-time")) { - priv->de_clear_time = (uint8_t) avr_atoi(value); - } - else { - return E_BAD_KEY; - } - - if (!suc) return E_BAD_VALUE; - return E_SUCCESS; -} - +extern error_t UUSART_loadIni(Unit *unit, const char *key, const char *value); /** Generate INI file section for the unit */ -static void UUSART_writeIni(Unit *unit, IniWriter *iw) -{ - struct priv *priv = unit->data; - - iw_comment(iw, "Peripheral number (UARTx 1-4)"); - iw_entry(iw, "device", "%d", (int)priv->periph_num); - - iw_comment(iw, "Pin mappings (TX,RX,CK,CTS,RTS/DE)"); -#if GEX_PLAT_F072_DISCOVERY - iw_comment(iw, " USART1: (0) A9,A10,A8,A11,A12 (1) B6,B7,A8,A11,A12"); - iw_comment(iw, " USART2: (0) A2,A3,A4,A0,A1 (1) A14,A15,A4,A0,A1"); - iw_comment(iw, " USART3: (0) B10,B11,B12,B13,B14"); - iw_comment(iw, " USART4: (0) A0,A1,C12,B7,A15 (1) C10,C11,C12,B7,A15"); -#elif GEX_PLAT_F103_BLUEPILL - #error "NO IMPL" -#elif GEX_PLAT_F303_DISCOVERY - #error "NO IMPL" -#elif GEX_PLAT_F407_DISCOVERY - #error "NO IMPL" -#else - #error "BAD PLATFORM!" -#endif - iw_entry(iw, "remap", "%d", (int)priv->remap); - - iw_cmt_newline(iw); - iw_comment(iw, "Baud rate in bps (eg. 9600, 115200)"); // TODO examples/range - iw_entry(iw, "baud-rate", "%d", (int)priv->baudrate); - - iw_comment(iw, "Parity type (NONE, ODD, EVEN)"); - iw_entry(iw, "parity", "%s", str_3(priv->parity, - 0, "NONE", - 1, "ODD", - 2, "EVEN")); - - iw_comment(iw, "Number of stop bits (0.5, 1, 1.5, 2)"); - iw_entry(iw, "stop-bits", "%s", str_4(priv->stopbits, - 0, "0.5", - 1, "1", - 2, "1.5", - 3, "2")); - - iw_comment(iw, "Bit order (LSB or MSB first)"); - iw_entry(iw, "first-bit", str_2((uint32_t)priv->lsb_first, - 0, "MSB", - 1, "LSB")); - - iw_comment(iw, "Word width (7,8,9) - including parity bit if used"); - iw_entry(iw, "word-width", "%d", (int)priv->width); - - iw_comment(iw, "Enabled lines (RX,TX,RXTX)"); - iw_entry(iw, "direction", str_3(priv->direction, - 1, "RX", - 2, "TX", - 3, "RXTX")); - - iw_comment(iw, "Hardware flow control (NONE, RTS, CTS, FULL)"); - iw_entry(iw, "hw-flow-control", "%s", str_4(priv->hw_flow_control, - 0, "NONE", - 1, "RTS", - 2, "CTS", - 3, "FULL")); - - iw_cmt_newline(iw); - iw_comment(iw, "Generate serial clock (Y,N)"); - iw_entry(iw, "clock-output", str_yn(priv->clock_output)); - iw_comment(iw, "Output clock polarity: 0,1 (clock idle level)"); - iw_entry(iw, "cpol", "%d", (int)priv->cpol); - iw_comment(iw, "Output clock phase: 0,1 (active edge, 0-first, 1-second)"); - iw_entry(iw, "cpha", "%d", (int)priv->cpha); - - iw_cmt_newline(iw); - iw_comment(iw, "Generate RS485 Driver Enable signal (Y,N) - uses RTS pin"); - iw_entry(iw, "de-output", str_yn(priv->de_output)); - iw_comment(iw, "DE active level: 0,1"); - iw_entry(iw, "de-polarity", "%d", (int)(priv->de_polarity)); - iw_comment(iw, "DE assert time (0-31)"); - iw_entry(iw, "de-assert-time", "%d", (int)(priv->de_assert_time)); - iw_comment(iw, "DE clear time (0-31)"); - iw_entry(iw, "de-clear-time", "%d", (int)(priv->de_clear_time)); -} - +extern void UUSART_writeIni(Unit *unit, IniWriter *iw); // ------------------------------------------------------------------------ - -/** Claim the peripheral and assign priv->periph */ -static error_t UUSART_ClaimPeripheral(Unit *unit) -{ - struct priv *priv = unit->data; - - if (!(priv->periph_num >= 1 && priv->periph_num <= 5)) { - dbg("!! Bad USART periph"); - return E_BAD_CONFIG; - } - - // assign and claim the peripheral - if (priv->periph_num == 1) { - TRY(rsc_claim(unit, R_USART1)); - priv->periph = USART1; - } - else if (priv->periph_num == 2) { - TRY(rsc_claim(unit, R_USART2)); - priv->periph = USART2; - } - else if (priv->periph_num == 3) { - TRY(rsc_claim(unit, R_USART3)); - priv->periph = USART3; - } -#if defined(USART4) - else if (priv->periph_num == 4) { - TRY(rsc_claim(unit, R_USART4)); - priv->periph = USART4; - } -#endif -#if defined(USART5) - else if (priv->periph_num == 5) { - TRY(rsc_claim(unit, R_USART5)); - priv->periph = USART5; - } -#endif - else return E_BAD_CONFIG; - - return E_SUCCESS; -} - -/** Claim and configure GPIOs used */ -static error_t UUSART_ConfigurePins(Unit *unit) -{ - struct priv *priv = unit->data; - // This is written for F072, other platforms will need adjustments - - // Configure UART pins (AF) - -#define want_ck_pin(priv) ((priv)->clock_output) -#define want_tx_pin(priv) (bool)((priv)->direction & 2) -#define want_rx_pin(priv) (bool)((priv)->direction & 1) -#define want_cts_pin(priv) ((priv)->hw_flow_control==2 || (priv)->hw_flow_control==3) -#define want_rts_pin(priv) ((priv)->de_output || (priv)->hw_flow_control==1 || (priv)->hw_flow_control==3) - - /* List of required pins based on the user config */ - bool pins_wanted[5] = { - want_ck_pin(priv), - want_tx_pin(priv), - want_rx_pin(priv), - want_cts_pin(priv), - want_rts_pin(priv) - }; - -#if GEX_PLAT_F072_DISCOVERY - - const struct PinAF *mappings = NULL; - - // TODO adjust this, possibly remove / split to individual pin config for .. - // the final board - - const struct PinAF mapping_1_0[5] = { - {'A', 8, LL_GPIO_AF_1}, // CK - {'A', 9, LL_GPIO_AF_1}, // TX - {'A', 10, LL_GPIO_AF_1}, // RX - {'A', 11, LL_GPIO_AF_1}, // CTS - collides with USB - {'A', 12, LL_GPIO_AF_1}, // RTS - collides with USB - }; - - const struct PinAF mapping_1_1[5] = { - {'A', 8, LL_GPIO_AF_1}, // CK* - {'B', 6, LL_GPIO_AF_1}, // TX - {'B', 7, LL_GPIO_AF_1}, // RX - {'A', 11, LL_GPIO_AF_1}, // CTS* - collides with USB - {'A', 12, LL_GPIO_AF_1}, // RTS* - collides with USB - }; - - const struct PinAF mapping_2_0[5] = { - {'A', 4, LL_GPIO_AF_1}, // CK - {'A', 2, LL_GPIO_AF_1}, // TX - {'A', 3, LL_GPIO_AF_1}, // RX - {'A', 0, LL_GPIO_AF_1}, // CTS - {'A', 1, LL_GPIO_AF_1}, // RTS - }; - - const struct PinAF mapping_2_1[5] = { - {'A', 4, LL_GPIO_AF_1}, // CK* - {'A', 14, LL_GPIO_AF_1}, // TX - {'A', 15, LL_GPIO_AF_1}, // RX - {'A', 0, LL_GPIO_AF_1}, // CTS* - {'A', 1, LL_GPIO_AF_1}, // RTS* - }; - - const struct PinAF mapping_3_0[5] = { - {'B', 12, LL_GPIO_AF_4}, // CK - {'B', 10, LL_GPIO_AF_4}, // TX - {'B', 11, LL_GPIO_AF_4}, // RX - {'B', 13, LL_GPIO_AF_4}, // CTS - {'B', 14, LL_GPIO_AF_4}, // RTS - }; - - const struct PinAF mapping_4_0[5] = { - {'C', 12, LL_GPIO_AF_0}, // CK - {'A', 0, LL_GPIO_AF_4}, // TX - {'A', 1, LL_GPIO_AF_4}, // RX - {'B', 7, LL_GPIO_AF_4}, // CTS - {'A', 15, LL_GPIO_AF_4}, // RTS - }; - - const struct PinAF mapping_4_1[5] = { - {'C', 12, LL_GPIO_AF_0}, // CK* - {'C', 10, LL_GPIO_AF_0}, // TX - {'C', 11, LL_GPIO_AF_0}, // RX - {'B', 7, LL_GPIO_AF_4}, // CTS* - {'A', 15, LL_GPIO_AF_4}, // RTS* - }; - - if (priv->periph_num == 1) { - // USART1 - if (priv->remap == 0) mappings = &mapping_1_0[0]; - else if (priv->remap == 1) mappings = &mapping_1_1[0]; - else return E_BAD_CONFIG; - } - else if (priv->periph_num == 2) { - // USART2 - if (priv->remap == 0) mappings = &mapping_2_0[0]; - else if (priv->remap == 1) mappings = &mapping_2_1[0]; - else return E_BAD_CONFIG; - } - else if (priv->periph_num == 3) { - // USART3 - if (priv->remap == 0) mappings = &mapping_3_0[0]; - else return E_BAD_CONFIG; - } - else if (priv->periph_num == 4) { - // USART3 - if (priv->remap == 0) mappings = &mapping_4_0[0]; - else if (priv->remap == 1) mappings = &mapping_4_1[0]; - else return E_BAD_CONFIG; - } - else return E_BAD_CONFIG; - - // Apply mappings based on the 'wanted' table - for (int i = 0; i < 5; i++) { - if (pins_wanted[i]) { - if (mappings[i].port == 0) return E_BAD_CONFIG; - TRY(rsc_claim_pin(unit, mappings[i].port, mappings[i].pin)); - hw_configure_gpio_af(mappings[i].port, mappings[i].pin, mappings[i].af); - } - } - -#elif GEX_PLAT_F103_BLUEPILL - #error "NO IMPL" -#elif GEX_PLAT_F303_DISCOVERY - #error "NO IMPL" -#elif GEX_PLAT_F407_DISCOVERY - #error "NO IMPL" -#else - #error "BAD PLATFORM!" -#endif - - return E_SUCCESS; -} - -/** Finalize unit set-up */ -static error_t UUSART_init(Unit *unit) -{ - bool suc = true; - struct priv *priv = unit->data; - - TRY(UUSART_ClaimPeripheral(unit)); - TRY(UUSART_ConfigurePins(unit)); - - // --- Configure the peripheral --- - - // Enable clock for the peripheral used - hw_periph_clock_enable(priv->periph); - - LL_USART_Disable(priv->periph); - { - LL_USART_DeInit(priv->periph); - LL_USART_SetBaudRate(priv->periph, PLAT_APB1_HZ, LL_USART_OVERSAMPLING_16, priv->baudrate); - - LL_USART_SetParity(priv->periph, - priv->parity == 0 ? LL_USART_PARITY_NONE : - priv->parity == 1 ? LL_USART_PARITY_ODD - : LL_USART_PARITY_EVEN); - - LL_USART_SetStopBitsLength(priv->periph, - priv->stopbits == 0 ? LL_USART_STOPBITS_0_5 : - priv->stopbits == 1 ? LL_USART_STOPBITS_1 : - priv->stopbits == 2 ? LL_USART_STOPBITS_1_5 - : LL_USART_STOPBITS_2); - - LL_USART_SetTransferDirection(priv->periph, - priv->direction == 1 ? LL_USART_DIRECTION_RX : - priv->direction == 2 ? LL_USART_DIRECTION_TX - : LL_USART_DIRECTION_TX_RX); - - LL_USART_SetHWFlowCtrl(priv->periph, - priv->hw_flow_control == 0 ? LL_USART_HWCONTROL_NONE : - priv->hw_flow_control == 1 ? LL_USART_HWCONTROL_RTS : - priv->hw_flow_control == 2 ? LL_USART_HWCONTROL_CTS - : LL_USART_HWCONTROL_RTS_CTS); - - LL_USART_ConfigClock(priv->periph, - priv->cpha ? LL_USART_PHASE_2EDGE : LL_USART_PHASE_1EDGE, - priv->cpol ? LL_USART_POLARITY_HIGH : LL_USART_POLARITY_LOW, - true); // clock on last bit - TODO configurable? - - if (priv->clock_output) - LL_USART_EnableSCLKOutput(priv->periph); - else - LL_USART_DisableSCLKOutput(priv->periph); - - LL_USART_SetTransferBitOrder(priv->periph, - priv->lsb_first ? LL_USART_BITORDER_LSBFIRST - : LL_USART_BITORDER_MSBFIRST); - - LL_USART_SetDataWidth(priv->periph, - priv->width == 7 ? LL_USART_DATAWIDTH_7B : - priv->width == 8 ? LL_USART_DATAWIDTH_8B - : LL_USART_DATAWIDTH_9B); - - LL_USART_SetBinaryDataLogic(priv->periph, - priv->data_inv ? LL_USART_BINARY_LOGIC_NEGATIVE - : LL_USART_BINARY_LOGIC_POSITIVE); - - LL_USART_SetRXPinLevel(priv->periph, priv->rx_inv ? LL_USART_RXPIN_LEVEL_INVERTED - : LL_USART_RXPIN_LEVEL_STANDARD); - - LL_USART_SetTXPinLevel(priv->periph, priv->tx_inv ? LL_USART_TXPIN_LEVEL_INVERTED - : LL_USART_TXPIN_LEVEL_STANDARD); - - if (priv->de_output) - LL_USART_EnableDEMode(priv->periph); - else - LL_USART_DisableDEMode(priv->periph); - - LL_USART_SetDESignalPolarity(priv->periph, - priv->de_polarity ? LL_USART_DE_POLARITY_HIGH - : LL_USART_DE_POLARITY_LOW); - - LL_USART_SetDEAssertionTime(priv->periph, priv->de_assert_time); - LL_USART_SetDEDeassertionTime(priv->periph, priv->de_clear_time); - } - LL_USART_Enable(priv->periph); - - return E_SUCCESS; -} - /** Tear down the unit */ -static void UUSART_deInit(Unit *unit) -{ - struct priv *priv = unit->data; - - // de-init the pins & peripheral only if inited correctly - if (unit->status == E_SUCCESS) { - assert_param(priv->periph); - LL_USART_DeInit(priv->periph); - - // Disable clock - hw_periph_clock_disable(priv->periph); - } - - // Release all resources - rsc_teardown(unit); - - // Free memory - free_ck(unit->data); - unit->data = NULL; -} - +extern void UUSART_deInit(Unit *unit); +/** Finalize unit set-up */ +extern error_t UUSART_init(Unit *unit); // ------------------------------------------------------------------------ static error_t usart_wait_until_flag(struct priv *priv, uint32_t flag, bool stop_state) diff --git a/utils/malloc_safe.c b/utils/malloc_safe.c index d14929a..fa57637 100644 --- a/utils/malloc_safe.c +++ b/utils/malloc_safe.c @@ -8,18 +8,14 @@ void *malloc_ck_do(size_t size, const char *file, uint32_t line) void *mem = pvPortMalloc(size); _malloc_trace(size, mem, file, line); if (mem == NULL) { - warn_msg("MALLOC FAILED", file, line); + _warn_msg(file, line, "MALLOC FAILED"); } return mem; } void *calloc_ck_do(size_t nmemb, size_t size, const char *file, uint32_t line) { - void *mem = pvPortMalloc(size*nmemb); - _malloc_trace(nmemb*size, mem, file, line); - if (mem == NULL) { - warn_msg("CALLOC FAILED", file, line); - } + void *mem = malloc_ck_do(nmemb*size, file, line); memset(mem, 0, size*nmemb); return mem; }