diff --git a/02_Arduino/hoverserial/hoverserial.ino b/02_Arduino/hoverserial/hoverserial.ino index 7382521..3897bc4 100644 --- a/02_Arduino/hoverserial/hoverserial.ino +++ b/02_Arduino/hoverserial/hoverserial.ino @@ -1,5 +1,5 @@ // ******************************************************************* -// Arduino Nano 3.3V example code +// Arduino Nano 5V example code // for https://github.com/EmanuelFeru/hoverboard-firmware-hack-FOC // // Copyright (C) 2019-2020 Emanuel FERU @@ -12,14 +12,14 @@ // • The data packaging includes a Start Frame, checksum, and re-syncronization capability for reliable communication // // CONFIGURATION on the hoverboard side in config.h: -// • Option 1: Serial on Left Sensor cable (long wired cable) -// #define CONTROL_SERIAL_USART2 -// #define FEEDBACK_SERIAL_USART2 -// // #define DEBUG_SERIAL_USART2 -// • Option 2: Serial on Right Sensor cable (short wired cable) - recommended, so the ADCs on the other cable are still available +// • Option 1: Serial on Right Sensor cable (short wired cable) - recommended, since the USART3 pins are 5V tolerant. // #define CONTROL_SERIAL_USART3 // #define FEEDBACK_SERIAL_USART3 // // #define DEBUG_SERIAL_USART3 +// • Option 2: Serial on Left Sensor cable (long wired cable) - use only with 3.3V devices! The USART2 pins are not 5V tolerant! +// #define CONTROL_SERIAL_USART2 +// #define FEEDBACK_SERIAL_USART2 +// // #define DEBUG_SERIAL_USART2 // ******************************************************************* // ########################## DEFINES ########################## diff --git a/Inc/config.h b/Inc/config.h index 31b4096..86fbe40 100644 --- a/Inc/config.h +++ b/Inc/config.h @@ -397,6 +397,7 @@ defined(FEEDBACK_SERIAL_USART3) || defined(CONTROL_SERIAL_USART3) || defined(DEBUG_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) #define SERIAL_START_FRAME 0xABCD // [-] Start frame definition for serial commands #define SERIAL_TIMEOUT 160 // [-] Serial timeout duration for the received data. 160 ~= 0.8 sec. Calculation: 0.8 sec / 0.005 sec + #define SERIAL_BUFFER_SIZE 64 // [bytes] Size of Serial Rx buffer. Make sure it is always larger than the structure size #endif #if defined(FEEDBACK_SERIAL_USART2) || defined(CONTROL_SERIAL_USART2) || defined(DEBUG_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) #ifndef USART2_BAUD @@ -408,12 +409,6 @@ #define USART3_BAUD 38400 // UART3 baud rate (short wired cable) #define USART3_WORDLENGTH UART_WORDLENGTH_8B // UART_WORDLENGTH_8B or UART_WORDLENGTH_9B #endif - -#if defined(DEBUG_SERIAL_USART2) - #define UART_DMA_CHANNEL_TX DMA1_Channel7 -#elif defined(DEBUG_SERIAL_USART3) - #define UART_DMA_CHANNEL_TX DMA1_Channel2 -#endif // ########################### UART SETIINGS ############################ diff --git a/Inc/defines.h b/Inc/defines.h index ddcbd6c..0371729 100644 --- a/Inc/defines.h +++ b/Inc/defines.h @@ -152,6 +152,7 @@ #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MIN3(a, b, c) MIN(a, MIN(b, c)) #define MAX3(a, b, c) MAX(a, MAX(b, c)) +#define ARRAY_LEN(x) (uint32_t)(sizeof(x) / sizeof(*(x))) typedef struct { uint16_t dcr; diff --git a/Inc/stm32f1xx_it.h b/Inc/stm32f1xx_it.h index 237a392..fa312a9 100644 --- a/Inc/stm32f1xx_it.h +++ b/Inc/stm32f1xx_it.h @@ -56,7 +56,13 @@ void DebugMon_Handler(void); void PendSV_Handler(void); void SysTick_Handler(void); void DMA1_Channel1_IRQHandler(void); +void DMA1_Channel2_IRQHandler(void); +void DMA1_Channel3_IRQHandler(void); +void DMA1_Channel6_IRQHandler(void); +void DMA1_Channel7_IRQHandler(void); void DMA2_Channel4_5_IRQHandler(void); +void USART2_IRQHandler(void); +void USART3_IRQHandler(void); #ifdef __cplusplus } diff --git a/Inc/util.h b/Inc/util.h index 07f8684..a7f9abb 100644 --- a/Inc/util.h +++ b/Inc/util.h @@ -31,14 +31,14 @@ uint8_t channels[IBUS_NUM_CHANNELS*2]; uint8_t checksuml; uint8_t checksumh; - } Serialcommand; + } SerialCommand; #else typedef struct{ uint16_t start; int16_t steer; int16_t speed; uint16_t checksum; - } Serialcommand; + } SerialCommand; #endif #endif #if defined(SIDEBOARD_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART3) @@ -73,6 +73,17 @@ void poweroffPressCheck(void); // Read Command Function void readCommand(void); +void usart2_rx_check(void); +void usart3_rx_check(void); +#if defined(DEBUG_SERIAL_USART2) || defined(DEBUG_SERIAL_USART3) +void usart_process_debug(uint8_t *userCommand, uint32_t len); +#endif +#if defined(CONTROL_SERIAL_USART2) || defined(CONTROL_SERIAL_USART3) +void usart_process_command(SerialCommand *command_in, SerialCommand *command_out, uint8_t usart_idx); +#endif +#if defined(SIDEBOARD_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART3) +void usart_process_sideboard(SerialSideboard *Sideboard_in, SerialSideboard *Sideboard_out, uint8_t usart_idx); +#endif int addDeadBand(int16_t u, int16_t deadBand, int16_t min, int16_t max); // Sideboard functions diff --git a/README.md b/README.md index e90f368..7f2770f 100644 --- a/README.md +++ b/README.md @@ -12,33 +12,24 @@ This repository implements Field Oriented Control (FOC) for stock hoverboards. C - [hoverboard-sideboard-hack-GD](https://github.com/EmanuelFeru/hoverboard-sideboard-hack-GD) - [hoverboard-sideboard-hack-STM](https://github.com/EmanuelFeru/hoverboard-sideboard-hack-STM) - --- - ## Hardware +--- +## Hardware ![mainboard_pinout](/docs/pictures/mainboard_pinout.png) -The original Hardware supports two 4-pin cables that originally were connected to the two sensor boards. They break out GND, 12/15V and USART2&3 of the Hoverboard mainboard. -Both USART2 & 3 can be used for UART and I2C, PA2&3 can be used as 12bit ADCs. +The original Hardware supports two 4-pin cables that originally were connected to the two sensor boards. They break out GND, 12/15V and USART2&3 of the Hoverboard mainboard. Both USART2&3 can be used for UART and I2C, PA2&3 can be used as 12bit ADCs. Note that while USART3 (right sideboard cable) is 5V tolerant, USART2 (left sideboard cable) is **not** 5V tolerant. -The reverse-engineered schematics of the mainboard can be found here: -http://vocke.tv/lib/exe/fetch.php?media=20150722_hoverboard_sch.pdf - - - --- - ## FOC Firmware - - This new firmware offers 3 control modes: - - **VOLTAGE MODE**: in this mode the controller applies a constant Voltage to the motors - - **SPEED MODE**: in this mode a closed-loop controller realizes the input target speed by rejecting any of the disturbance (resistive load) applied to the motor - - **TORQUE MODE**: in this mode the target torque set by the user is realized. This mode enables motor "freewheeling" when the torque target is "0". Recommended for most applications with a sitting human driver. If you want the motor to brake instead of "freewheel" when torque target is "0", modify code to set torque target below "0" when `speedAvgAbs > 0`. - -In all the modes, the controller features maximum motor speed and maximum motor current protection. This brings great advantages to fulfil the needs of many robotic applications while maintaining safe operation. - - The C code for the controller was auto-code generated using [Matlab/Simulink](https://nl.mathworks.com/solutions/embedded-code-generation.html) from a model which I developed from scratch specifically for hoverboard control. For more details regarding the working principle of the controller please consult the [Matlab/Simulink model](/01_Matlab). - - A [webview](/01_Matlab/BLDC_controller_ert_rtw/html/webview) was created, so Matlab/Simulink installation is not needed, unless you want to regenerate the code. The webview is an html page that can be opened with browsers like: Microsoft Internet Explorer or Microsoft Edge. +Typically, the mainboard brain is an [STM32F103RCT6](/docs/literatur/[10]_STM32F103xC_datasheet.pdf), however some mainboards feature a [GD32F103RCT6](/docs/literatur/[11]_GD32F103xx-Datasheet-Rev-2.7.pdf) which is also supported by this firmware. +For the reverse-engineered schematics of the mainboard, see [20150722_hoverboard_sch.pdf](/docs/20150722_hoverboard_sch.pdf) + + +--- +## FOC Firmware + ### Firmware Architecture -The main firmware architecture includes: +The firmware architecture includes: - **Estimations**: estimates the rotor position, angle and motor speed based on Hall sensors signal - **Diagnostics**: implements error detection such as unconnected Hall sensor, motor blocked, MOSFET defective - **Control Manager**: manages the transitions between control modes (Voltage, Speed, Torque) @@ -54,8 +45,18 @@ The FOC algorithm architecture is illustrated in the figure below: In this firmware 3 control types are available: - Commutation - SIN (Sinusoidal) -- FOC (Field Oriented Control) +- FOC (Field Oriented Control) with the following 3 control modes: + - **VOLTAGE MODE**: in this mode the controller applies a constant Voltage to the motors + - **SPEED MODE**: in this mode a closed-loop controller realizes the input speed target by rejecting any of the disturbance (resistive load) applied to the motor + - **TORQUE MODE**: in this mode the input torque target is realized. This mode enables motor "freewheeling" when the torque target is `0`. Recommended for most applications with a sitting human driver. If motor braking is desired instead of "freewheel" when torque target is `0`, then a torque target below `0` should be set when `speedAvgAbs > 0`. + ![Schematic representation of the available control methods](/01_Matlab/02_Figures/control_methods.png) + +In all FOC control modes, the controller features maximum motor speed and maximum motor current protection. This brings great advantages to fulfil the needs of many robotic applications while maintaining safe operation. + +The C code for the controller was auto-code generated using [Matlab/Simulink](https://nl.mathworks.com/solutions/embedded-code-generation.html) from a model which I developed from scratch specifically for hoverboard control. For more details regarding the working principle of the controller please consult the [Matlab/Simulink model](/01_Matlab). + +A [webview](/01_Matlab/BLDC_controller_ert_rtw/html/webview) was created, so Matlab/Simulink installation is not needed, unless you want to regenerate the code. The webview is an html page that can be opened with browsers like: Microsoft Internet Explorer or Microsoft Edge. ### Field Weakening / Phase Advance diff --git a/Src/comms.c b/Src/comms.c index bab9dde..61ee47d 100644 --- a/Src/comms.c +++ b/Src/comms.c @@ -30,12 +30,16 @@ void consoleScope(void) { uart_buf[8] = CLAMP(ch_buf[7]+127, 0, 255); uart_buf[9] = '\n'; - if(UART_DMA_CHANNEL_TX->CNDTR == 0) { - UART_DMA_CHANNEL_TX->CCR &= ~DMA_CCR_EN; - UART_DMA_CHANNEL_TX->CNDTR = 10; - UART_DMA_CHANNEL_TX->CMAR = (uint32_t)uart_buf; - UART_DMA_CHANNEL_TX->CCR |= DMA_CCR_EN; + #ifdef DEBUG_SERIAL_USART2 + if(__HAL_DMA_GET_COUNTER(huart2.hdmatx) == 0) { + HAL_UART_Transmit_DMA(&huart2, (uint8_t *)uart_buf, strLength); } + #endif + #ifdef DEBUG_SERIAL_USART3 + if(__HAL_DMA_GET_COUNTER(huart3.hdmatx) == 0) { + HAL_UART_Transmit_DMA(&huart3, (uint8_t *)uart_buf, strLength); + } + #endif #endif #if defined DEBUG_SERIAL_ASCII && (defined DEBUG_SERIAL_USART2 || defined DEBUG_SERIAL_USART3) @@ -44,24 +48,34 @@ void consoleScope(void) { strLength = sprintf((char *)(uintptr_t)uart_buf, "1:%i 2:%i 3:%i 4:%i 5:%i 6:%i 7:%i 8:%i\r\n", ch_buf[0], ch_buf[1], ch_buf[2], ch_buf[3], ch_buf[4], ch_buf[5], ch_buf[6], ch_buf[7]); - - if(UART_DMA_CHANNEL_TX->CNDTR == 0) { - UART_DMA_CHANNEL_TX->CCR &= ~DMA_CCR_EN; - UART_DMA_CHANNEL_TX->CNDTR = strLength; - UART_DMA_CHANNEL_TX->CMAR = (uint32_t)uart_buf; - UART_DMA_CHANNEL_TX->CCR |= DMA_CCR_EN; + + #ifdef DEBUG_SERIAL_USART2 + if(__HAL_DMA_GET_COUNTER(huart2.hdmatx) == 0) { + HAL_UART_Transmit_DMA(&huart2, (uint8_t *)uart_buf, strLength); } + #endif + #ifdef DEBUG_SERIAL_USART3 + if(__HAL_DMA_GET_COUNTER(huart3.hdmatx) == 0) { + HAL_UART_Transmit_DMA(&huart3, (uint8_t *)uart_buf, strLength); + } + #endif #endif + + } void consoleLog(char *message) { #if defined DEBUG_SERIAL_ASCII && (defined DEBUG_SERIAL_USART2 || defined DEBUG_SERIAL_USART3) - if(UART_DMA_CHANNEL_TX->CNDTR == 0) { - UART_DMA_CHANNEL_TX->CCR &= ~DMA_CCR_EN; - UART_DMA_CHANNEL_TX->CNDTR = strlen((char *)(uintptr_t)message); - UART_DMA_CHANNEL_TX->CMAR = (uint32_t)message; - UART_DMA_CHANNEL_TX->CCR |= DMA_CCR_EN; + #ifdef DEBUG_SERIAL_USART2 + if(__HAL_DMA_GET_COUNTER(huart2.hdmatx) == 0) { + HAL_UART_Transmit_DMA(&huart2, (uint8_t *)message, strlen((char *)(uintptr_t)message)); } + #endif + #ifdef DEBUG_SERIAL_USART3 + if(__HAL_DMA_GET_COUNTER(huart3.hdmatx) == 0) { + HAL_UART_Transmit_DMA(&huart3, (uint8_t *)message, strlen((char *)(uintptr_t)message)); + } + #endif #endif } diff --git a/Src/main.c b/Src/main.c index de2b5c3..969c04f 100644 --- a/Src/main.c +++ b/Src/main.c @@ -49,6 +49,9 @@ extern volatile adc_buf_t adc_buffer; extern uint8_t LCDerrorFlag; #endif +extern UART_HandleTypeDef huart2; +extern UART_HandleTypeDef huart3; + // Matlab defines - from auto-code generation //--------------- extern P rtP_Left; /* Block parameters (auto storage) */ @@ -206,6 +209,7 @@ int main(void) { shortBeep(6); // make 2 beeps indicating the motor enable shortBeep(4); HAL_Delay(100); enable = 1; // enable motors + consoleLog("-- Motors enabled --\r\n"); } // ####### VARIANT_HOVERCAR ####### @@ -418,25 +422,21 @@ int main(void) { Feedback.boardTemp = (int16_t)board_temp_deg_c; #if defined(FEEDBACK_SERIAL_USART2) - if(DMA1_Channel7->CNDTR == 0) { + if(__HAL_DMA_GET_COUNTER(huart2.hdmatx) == 0) { Feedback.cmdLed = (uint16_t)sideboard_leds_L; Feedback.checksum = (uint16_t)(Feedback.start ^ Feedback.cmd1 ^ Feedback.cmd2 ^ Feedback.speedR_meas ^ Feedback.speedL_meas ^ Feedback.batVoltage ^ Feedback.boardTemp ^ Feedback.cmdLed); - DMA1_Channel7->CCR &= ~DMA_CCR_EN; - DMA1_Channel7->CNDTR = sizeof(Feedback); - DMA1_Channel7->CMAR = (uint32_t)&Feedback; - DMA1_Channel7->CCR |= DMA_CCR_EN; + + HAL_UART_Transmit_DMA(&huart2, (uint8_t *)&Feedback, sizeof(Feedback)); } #endif #if defined(FEEDBACK_SERIAL_USART3) - if(DMA1_Channel2->CNDTR == 0) { + if(__HAL_DMA_GET_COUNTER(huart3.hdmatx) == 0) { Feedback.cmdLed = (uint16_t)sideboard_leds_R; Feedback.checksum = (uint16_t)(Feedback.start ^ Feedback.cmd1 ^ Feedback.cmd2 ^ Feedback.speedR_meas ^ Feedback.speedL_meas ^ Feedback.batVoltage ^ Feedback.boardTemp ^ Feedback.cmdLed); - DMA1_Channel2->CCR &= ~DMA_CCR_EN; - DMA1_Channel2->CNDTR = sizeof(Feedback); - DMA1_Channel2->CMAR = (uint32_t)&Feedback; - DMA1_Channel2->CCR |= DMA_CCR_EN; + + HAL_UART_Transmit_DMA(&huart3, (uint8_t *)&Feedback, sizeof(Feedback)); } #endif } diff --git a/Src/setup.c b/Src/setup.c index 49b2d5b..f6059bb 100644 --- a/Src/setup.c +++ b/Src/setup.c @@ -37,6 +37,7 @@ pb10 usart3 dma1 channel2/3 #include "defines.h" #include "config.h" +#include "setup.h" TIM_HandleTypeDef htim_right; TIM_HandleTypeDef htim_left; @@ -53,178 +54,227 @@ DMA_HandleTypeDef hdma_usart3_tx; volatile adc_buf_t adc_buffer; -#if defined(CONTROL_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) || \ - defined(FEEDBACK_SERIAL_USAR2) || defined(DEBUG_SERIAL_USART2) -void UART2_Init(void) { - - /* The code below is commented out - otwerwise Serial Receive does not work */ - // #if defined(CONTROL_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART3) - // /* DMA1_Channel6_IRQn interrupt configuration */ - // HAL_NVIC_SetPriority(DMA1_Channel6_IRQn, 5, 6); - // HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn); - // /* DMA1_Channel7_IRQn interrupt configuration */ - // HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 5, 7); - // HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn); - // #endif - - // Disable serial interrupt - it is not needed - HAL_NVIC_DisableIRQ(DMA1_Channel6_IRQn); // Rx Channel - HAL_NVIC_DisableIRQ(DMA1_Channel7_IRQn); // Tx Channel - +#if defined(DEBUG_SERIAL_USART2) || defined(CONTROL_SERIAL_USART2) || defined(FEEDBACK_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) + /* USART2 init function */ + void UART2_Init(void) +{ + /* DMA controller clock enable */ __HAL_RCC_DMA1_CLK_ENABLE(); - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_USART2_CLK_ENABLE(); - - huart2.Instance = USART2; - huart2.Init.BaudRate = USART2_BAUD; - huart2.Init.WordLength = USART2_WORDLENGTH; - huart2.Init.StopBits = UART_STOPBITS_1; - huart2.Init.Parity = UART_PARITY_NONE; - huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; - huart2.Init.OverSampling = UART_OVERSAMPLING_16; - #if defined(CONTROL_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) - huart2.Init.Mode = UART_MODE_TX_RX; - #elif defined(FEEDBACK_SERIAL_USART2) || defined(DEBUG_SERIAL_USART2) - huart2.Init.Mode = UART_MODE_TX; - #endif + + /* DMA1_Channel6_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA1_Channel6_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn); + /* DMA1_Channel7_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn); + + huart2.Instance = USART2; + huart2.Init.BaudRate = USART2_BAUD; + huart2.Init.WordLength = USART2_WORDLENGTH; + huart2.Init.StopBits = UART_STOPBITS_1; + huart2.Init.Parity = UART_PARITY_NONE; + huart2.Init.Mode = UART_MODE_TX_RX; + huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; + huart2.Init.OverSampling = UART_OVERSAMPLING_16; HAL_UART_Init(&huart2); +} +#endif - #if defined(FEEDBACK_SERIAL_USART2) || defined(DEBUG_SERIAL_USART2) - USART2->CR3 |= USART_CR3_DMAT; // | USART_CR3_DMAR | USART_CR3_OVRDIS; - #endif +#if defined(DEBUG_SERIAL_USART3) || defined(CONTROL_SERIAL_USART3) || defined(FEEDBACK_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) +/* USART3 init function */ +void UART3_Init(void) +{ + /* DMA controller clock enable */ + __HAL_RCC_DMA1_CLK_ENABLE(); - GPIO_InitTypeDef GPIO_InitStruct; - GPIO_InitStruct.Pin = GPIO_PIN_2; - GPIO_InitStruct.Pull = GPIO_PULLUP; //GPIO_NOPULL; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + /* DMA interrupt init */ + /* DMA1_Channel2_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn); + /* DMA1_Channel3_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn); + + huart3.Instance = USART3; + huart3.Init.BaudRate = USART3_BAUD; + huart3.Init.WordLength = USART3_WORDLENGTH; + huart3.Init.StopBits = UART_STOPBITS_1; + huart3.Init.Parity = UART_PARITY_NONE; + huart3.Init.Mode = UART_MODE_TX_RX; + huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE; + huart3.Init.OverSampling = UART_OVERSAMPLING_16; + HAL_UART_Init(&huart3); +} +#endif - #if defined(CONTROL_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) - GPIO_InitStruct.Pin = GPIO_PIN_3; - GPIO_InitStruct.Mode = GPIO_MODE_INPUT; //GPIO_MODE_AF_PP; +void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) +{ + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(uartHandle->Instance==USART2) + { + /* USER CODE BEGIN USART2_MspInit 0 */ + + /* USER CODE END USART2_MspInit 0 */ + /* USART2 clock enable */ + __HAL_RCC_USART2_CLK_ENABLE(); + + __HAL_RCC_GPIOA_CLK_ENABLE(); + /**USART2 GPIO Configuration + PA2 ------> USART2_TX + PA3 ------> USART2_RX + */ + GPIO_InitStruct.Pin = GPIO_PIN_2; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - /* Peripheral DMA init*/ - hdma_usart2_rx.Instance = DMA1_Channel6; - hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; - hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE; - hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE; + GPIO_InitStruct.Pin = GPIO_PIN_3; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLUP; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /* USART2 DMA Init */ + /* USART2_RX Init */ + hdma_usart2_rx.Instance = DMA1_Channel6; + hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; - hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; - hdma_usart2_rx.Init.Mode = DMA_CIRCULAR; //DMA_NORMAL; - hdma_usart2_rx.Init.Priority = DMA_PRIORITY_LOW; + hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_usart2_rx.Init.Mode = DMA_CIRCULAR; + hdma_usart2_rx.Init.Priority = DMA_PRIORITY_LOW; HAL_DMA_Init(&hdma_usart2_rx); - __HAL_LINKDMA(&huart2, hdmarx, hdma_usart2_rx); - #endif + __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart2_rx); - hdma_usart2_tx.Instance = DMA1_Channel7; - hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; - hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE; - hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE; - hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; - hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; - hdma_usart2_tx.Init.Mode = DMA_NORMAL; - hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW; - HAL_DMA_Init(&hdma_usart2_tx); + /* USART2_TX Init */ + hdma_usart2_tx.Instance = DMA1_Channel7; + hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_usart2_tx.Init.Mode = DMA_NORMAL; + hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW; + HAL_DMA_Init(&hdma_usart2_tx); + __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart2_tx); - #if defined(CONTROL_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) - __HAL_LINKDMA(&huart2, hdmatx, hdma_usart2_tx); - #endif - #if defined(FEEDBACK_SERIAL_USART2) || defined(DEBUG_SERIAL_USART2) - DMA1_Channel7->CPAR = (uint32_t) & (USART2->DR); - DMA1_Channel7->CNDTR = 0; - DMA1->IFCR = DMA_IFCR_CTCIF7 | DMA_IFCR_CHTIF7 | DMA_IFCR_CGIF7; - #endif + /* USART2 interrupt Init */ + HAL_NVIC_SetPriority(USART2_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(USART2_IRQn); + /* USER CODE BEGIN USART2_MspInit 1 */ + __HAL_UART_ENABLE_IT (uartHandle, UART_IT_IDLE); // Enable the USART IDLE line detection interrupt + /* USER CODE END USART2_MspInit 1 */ + } + else if(uartHandle->Instance==USART3) + { + /* USER CODE BEGIN USART3_MspInit 0 */ -} -#endif - -#if defined(CONTROL_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) || \ - defined(FEEDBACK_SERIAL_USART3) || defined(DEBUG_SERIAL_USART3) -void UART3_Init(void) { - - /* The code below is commented out - otwerwise Serial Receive does not work */ - // #if defined(CONTROL_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) - // /* DMA1_Channel3_IRQn interrupt configuration */ - // HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 5, 3); - // HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn); - // /* DMA1_Channel2_IRQn interrupt configuration */ - // HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 5, 2); - // HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn); - // #endif - - // Disable serial interrupt - it is not needed - HAL_NVIC_DisableIRQ(DMA1_Channel3_IRQn); // Rx Channel - HAL_NVIC_DisableIRQ(DMA1_Channel2_IRQn); // Tx Channel - - __HAL_RCC_DMA1_CLK_ENABLE(); - __HAL_RCC_GPIOB_CLK_ENABLE(); - __HAL_RCC_USART3_CLK_ENABLE(); - - huart3.Instance = USART3; - huart3.Init.BaudRate = USART3_BAUD; - huart3.Init.WordLength = USART3_WORDLENGTH; - huart3.Init.StopBits = UART_STOPBITS_1; - huart3.Init.Parity = UART_PARITY_NONE; - huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE; - huart3.Init.OverSampling = UART_OVERSAMPLING_16; - #if defined(CONTROL_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) - huart3.Init.Mode = UART_MODE_TX_RX; - #elif defined(FEEDBACK_SERIAL_USART3) || defined(DEBUG_SERIAL_USART3) - huart3.Init.Mode = UART_MODE_TX; - #endif - HAL_UART_Init(&huart3); - - #if defined(FEEDBACK_SERIAL_USART3) || defined(DEBUG_SERIAL_USART3) - USART3->CR3 |= USART_CR3_DMAT; // | USART_CR3_DMAR | USART_CR3_OVRDIS; - #endif - - GPIO_InitTypeDef GPIO_InitStruct; - GPIO_InitStruct.Pin = GPIO_PIN_10; - GPIO_InitStruct.Pull = GPIO_PULLUP; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - - #if defined(CONTROL_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) - GPIO_InitStruct.Pin = GPIO_PIN_11; - GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + /* USER CODE END USART3_MspInit 0 */ + /* USART3 clock enable */ + __HAL_RCC_USART3_CLK_ENABLE(); + + __HAL_RCC_GPIOB_CLK_ENABLE(); + /**USART3 GPIO Configuration + PB10 ------> USART3_TX + PB11 ------> USART3_RX + */ + GPIO_InitStruct.Pin = GPIO_PIN_10; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - /* Peripheral DMA init*/ - hdma_usart3_rx.Instance = DMA1_Channel3; - hdma_usart3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; - hdma_usart3_rx.Init.PeriphInc = DMA_PINC_DISABLE; - hdma_usart3_rx.Init.MemInc = DMA_MINC_ENABLE; - hdma_usart3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; - hdma_usart3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; - hdma_usart3_rx.Init.Mode = DMA_CIRCULAR; //DMA_NORMAL; - hdma_usart3_rx.Init.Priority = DMA_PRIORITY_LOW; + GPIO_InitStruct.Pin = GPIO_PIN_11; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLUP; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /* USART3 DMA Init */ + /* USART3_RX Init */ + hdma_usart3_rx.Instance = DMA1_Channel3; + hdma_usart3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_usart3_rx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_usart3_rx.Init.MemInc = DMA_MINC_ENABLE; + hdma_usart3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_usart3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_usart3_rx.Init.Mode = DMA_CIRCULAR; + hdma_usart3_rx.Init.Priority = DMA_PRIORITY_LOW; HAL_DMA_Init(&hdma_usart3_rx); - __HAL_LINKDMA(&huart3, hdmarx, hdma_usart3_rx); - #endif + __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart3_rx); - hdma_usart3_tx.Instance = DMA1_Channel2; - hdma_usart3_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; - hdma_usart3_tx.Init.PeriphInc = DMA_PINC_DISABLE; - hdma_usart3_tx.Init.MemInc = DMA_MINC_ENABLE; - hdma_usart3_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; - hdma_usart3_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; - hdma_usart3_tx.Init.Mode = DMA_NORMAL; - hdma_usart3_tx.Init.Priority = DMA_PRIORITY_LOW; - HAL_DMA_Init(&hdma_usart3_tx); + /* USART3_TX Init */ + hdma_usart3_tx.Instance = DMA1_Channel2; + hdma_usart3_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_usart3_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_usart3_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_usart3_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_usart3_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_usart3_tx.Init.Mode = DMA_NORMAL; + hdma_usart3_tx.Init.Priority = DMA_PRIORITY_LOW; + HAL_DMA_Init(&hdma_usart3_tx); + __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart3_tx); - #if defined(CONTROL_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) - __HAL_LINKDMA(&huart3, hdmatx, hdma_usart3_tx); - #endif - #if defined(FEEDBACK_SERIAL_USART3) || defined(DEBUG_SERIAL_USART3) - DMA1_Channel2->CPAR = (uint32_t) & (USART3->DR); - DMA1_Channel2->CNDTR = 0; - DMA1->IFCR = DMA_IFCR_CTCIF2 | DMA_IFCR_CHTIF2 | DMA_IFCR_CGIF2; - #endif + /* USART3 interrupt Init */ + HAL_NVIC_SetPriority(USART3_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(USART3_IRQn); + /* USER CODE BEGIN USART3_MspInit 1 */ + __HAL_UART_ENABLE_IT (uartHandle, UART_IT_IDLE); // Enable the USART IDLE line detection interrupt + /* USER CODE END USART3_MspInit 1 */ + } } -#endif + +void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle) +{ + + if(uartHandle->Instance==USART2) + { + /* USER CODE BEGIN USART2_MspDeInit 0 */ + + /* USER CODE END USART2_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_USART2_CLK_DISABLE(); + + /**USART2 GPIO Configuration + PA2 ------> USART2_TX + PA3 ------> USART2_RX + */ + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3); + + /* USART2 DMA DeInit */ + HAL_DMA_DeInit(uartHandle->hdmarx); + HAL_DMA_DeInit(uartHandle->hdmatx); + + /* USART2 interrupt Deinit */ + HAL_NVIC_DisableIRQ(USART2_IRQn); + /* USER CODE BEGIN USART2_MspDeInit 1 */ + + /* USER CODE END USART2_MspDeInit 1 */ + } + else if(uartHandle->Instance==USART3) + { + /* USER CODE BEGIN USART3_MspDeInit 0 */ + + /* USER CODE END USART3_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_USART3_CLK_DISABLE(); + + /**USART3 GPIO Configuration + PB10 ------> USART3_TX + PB11 ------> USART3_RX + */ + HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10|GPIO_PIN_11); + + /* USART3 DMA DeInit */ + HAL_DMA_DeInit(uartHandle->hdmarx); + HAL_DMA_DeInit(uartHandle->hdmatx); + + /* USART3 interrupt Deinit */ + HAL_NVIC_DisableIRQ(USART3_IRQn); + /* USER CODE BEGIN USART3_MspDeInit 1 */ + + /* USER CODE END USART3_MspDeInit 1 */ + } +} + DMA_HandleTypeDef hdma_i2c2_rx; DMA_HandleTypeDef hdma_i2c2_tx; diff --git a/Src/stm32f1xx_it.c b/Src/stm32f1xx_it.c index 5c1dbcb..be3e863 100644 --- a/Src/stm32f1xx_it.c +++ b/Src/stm32f1xx_it.c @@ -36,6 +36,7 @@ #include "stm32f1xx_it.h" #include "defines.h" #include "config.h" +#include "util.h" extern DMA_HandleTypeDef hdma_i2c2_rx; extern DMA_HandleTypeDef hdma_i2c2_tx; @@ -43,9 +44,12 @@ extern I2C_HandleTypeDef hi2c2; extern DMA_HandleTypeDef hdma_usart2_rx; extern DMA_HandleTypeDef hdma_usart2_tx; +extern DMA_HandleTypeDef hdma_usart3_rx; +extern DMA_HandleTypeDef hdma_usart3_tx; /* USER CODE BEGIN 0 */ - +extern UART_HandleTypeDef huart2; +extern UART_HandleTypeDef huart3; /* USER CODE END 0 */ /* External variables --------------------------------------------------------*/ @@ -250,7 +254,7 @@ void EXTI2_IRQHandler(void) } #endif -#ifdef CONTROL_SERIAL_USART2 +#if defined(DEBUG_SERIAL_USART2) || defined(CONTROL_SERIAL_USART2) || defined(FEEDBACK_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) void DMA1_Channel6_IRQHandler(void) { /* USER CODE BEGIN DMA1_Channel4_IRQn 0 */ @@ -277,6 +281,74 @@ void DMA1_Channel7_IRQHandler(void) } #endif +#if defined(DEBUG_SERIAL_USART3) || defined(CONTROL_SERIAL_USART3) || defined(FEEDBACK_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) +/** + * @brief This function handles DMA1 channel2 global interrupt. + */ +void DMA1_Channel2_IRQHandler(void) +{ + /* USER CODE BEGIN DMA1_Channel2_IRQn 0 */ + + /* USER CODE END DMA1_Channel2_IRQn 0 */ + HAL_DMA_IRQHandler(&hdma_usart3_tx); + /* USER CODE BEGIN DMA1_Channel2_IRQn 1 */ + + /* USER CODE END DMA1_Channel2_IRQn 1 */ +} + +/** + * @brief This function handles DMA1 channel3 global interrupt. + */ +void DMA1_Channel3_IRQHandler(void) +{ + /* USER CODE BEGIN DMA1_Channel3_IRQn 0 */ + + /* USER CODE END DMA1_Channel3_IRQn 0 */ + HAL_DMA_IRQHandler(&hdma_usart3_rx); + /* USER CODE BEGIN DMA1_Channel3_IRQn 1 */ + + /* USER CODE END DMA1_Channel3_IRQn 1 */ +} +#endif + +#if defined(DEBUG_SERIAL_USART2) || defined(CONTROL_SERIAL_USART2) || defined(FEEDBACK_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) +/** + * @brief This function handles USART2 global interrupt. + */ +void USART2_IRQHandler(void) +{ + /* USER CODE BEGIN USART2_IRQn 0 */ + + /* USER CODE END USART2_IRQn 0 */ + HAL_UART_IRQHandler(&huart2); + /* USER CODE BEGIN USART2_IRQn 1 */ + if(RESET != __HAL_UART_GET_IT_SOURCE(&huart2, UART_IT_IDLE)) { // Check for IDLE line interrupt + __HAL_UART_CLEAR_IDLEFLAG(&huart2); // Clear IDLE line flag (otherwise it will continue to enter interrupt) + usart2_rx_check(); // Check for data to process + } + /* USER CODE END USART2_IRQn 1 */ +} +#endif + +#if defined(DEBUG_SERIAL_USART3) || defined(CONTROL_SERIAL_USART3) || defined(FEEDBACK_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) +/** + * @brief This function handles USART3 global interrupt. + */ +void USART3_IRQHandler(void) +{ + /* USER CODE BEGIN USART2_IRQn 0 */ + + /* USER CODE END USART2_IRQn 0 */ + HAL_UART_IRQHandler(&huart3); + /* USER CODE BEGIN USART2_IRQn 1 */ + if(RESET != __HAL_UART_GET_IT_SOURCE(&huart3, UART_IT_IDLE)) { // Check for IDLE line interrupt + __HAL_UART_CLEAR_IDLEFLAG(&huart3); // Clear IDLE line flag (otherwise it will continue to enter interrupt) + usart3_rx_check(); // Check for data to process + } + /* USER CODE END USART2_IRQn 1 */ +} +#endif + /******************************************************************************/ /* STM32F1xx Peripheral Interrupt Handlers */ /* Add here the Interrupt Handlers for the used peripherals. */ diff --git a/Src/util.c b/Src/util.c index 629273a..0371ce9 100644 --- a/Src/util.c +++ b/Src/util.c @@ -41,12 +41,8 @@ //------------------------------------------------------------------------ extern volatile adc_buf_t adc_buffer; extern I2C_HandleTypeDef hi2c2; -#if defined(CONTROL_SERIAL_USART2) || defined(FEEDBACK_SERIAL_USART2) || defined(DEBUG_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) \ - || defined(CONTROL_SERIAL_USART3) || defined(FEEDBACK_SERIAL_USART3) || defined(DEBUG_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) - extern UART_HandleTypeDef huart2; - extern UART_HandleTypeDef huart3; - static UART_HandleTypeDef huart; -#endif +extern UART_HandleTypeDef huart2; +extern UART_HandleTypeDef huart3; extern int16_t batVoltage; extern uint8_t backwardDrive; @@ -106,23 +102,39 @@ uint8_t timeoutFlagSerial = 0; // Timeout Flag for Rx Serial command: 0 uint8_t ctrlModReqRaw = CTRL_MOD_REQ; uint8_t ctrlModReq = CTRL_MOD_REQ; // Final control mode request +#if defined(DEBUG_SERIAL_USART2) || defined(CONTROL_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) +uint8_t rx_buffer_L[SERIAL_BUFFER_SIZE]; // USART Rx DMA circular buffer +static uint32_t rx_buffer_L_len = ARRAY_LEN(rx_buffer_L); +#endif +#if defined(CONTROL_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) +static int16_t timeoutCntSerial_L = 0; // Timeout counter for Rx Serial command +static uint8_t timeoutFlagSerial_L = 0; // Timeout Flag for Rx Serial command: 0 = OK, 1 = Problem detected (line disconnected or wrong Rx data) +#endif #if defined(SIDEBOARD_SERIAL_USART2) SerialSideboard Sideboard_L; -static SerialSideboard Sideboard_Lnew; -static uint8_t timeoutFlagSerial_L = 0; -static int16_t timeoutCntSerial_L = 0; +SerialSideboard Sideboard_L_raw; +static uint32_t Sideboard_L_len = sizeof(Sideboard_L); +#endif + +#if defined(DEBUG_SERIAL_USART3) || defined(CONTROL_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) +uint8_t rx_buffer_R[SERIAL_BUFFER_SIZE]; // USART Rx DMA circular buffer +static uint32_t rx_buffer_R_len = ARRAY_LEN(rx_buffer_R); +#endif +#if defined(CONTROL_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) +static int16_t timeoutCntSerial_R = 0; // Timeout counter for Rx Serial command +static uint8_t timeoutFlagSerial_R = 0; // Timeout Flag for Rx Serial command: 0 = OK, 1 = Problem detected (line disconnected or wrong Rx data) #endif #if defined(SIDEBOARD_SERIAL_USART3) SerialSideboard Sideboard_R; -static SerialSideboard Sideboard_Rnew; -static uint8_t timeoutFlagSerial_R = 0; -static int16_t timeoutCntSerial_R = 0; -#endif +SerialSideboard Sideboard_R_raw; +static uint32_t Sideboard_R_len = sizeof(Sideboard_R); +#endif + #if !defined(VARIANT_HOVERBOARD) && (defined(SIDEBOARD_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART3)) static uint8_t sensor1_prev; // holds the previous sensor1 state static uint8_t sensor2_prev; // holds the previous sensor2 state -static uint8_t sensor1_index; // holds the press index number for sensor1 -static uint8_t sensor2_index; // holds the press index number for sensor2 +static uint8_t sensor1_index; // holds the press index number for sensor1, when used as a button +static uint8_t sensor2_index; // holds the press index number for sensor2, when used as a button #endif #if defined(DEBUG_I2C_LCD) || defined(SUPPORT_LCD) @@ -158,8 +170,9 @@ static int16_t timeoutCntADC = 0; // Timeout counter for ADC Protection #endif #if defined(CONTROL_SERIAL_USART2) || defined(CONTROL_SERIAL_USART3) -static int16_t timeoutCntSerial = 0; // Timeout counter for Rx Serial command -static volatile Serialcommand command; +static SerialCommand command; +static SerialCommand command_raw; +static uint32_t command_len = sizeof(command); #ifdef CONTROL_IBUS static uint16_t ibus_chksum; static uint16_t ibus_captured_value[IBUS_NUM_CHANNELS]; @@ -253,22 +266,17 @@ void Input_Init(void) { Nunchuk_Init(); #endif - #if defined(CONTROL_SERIAL_USART2) || defined(FEEDBACK_SERIAL_USART2) || defined(DEBUG_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) + #if defined(DEBUG_SERIAL_USART2) || defined(CONTROL_SERIAL_USART2) || defined(FEEDBACK_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) UART2_Init(); - huart = huart2; #endif - #if defined(CONTROL_SERIAL_USART3) || defined(FEEDBACK_SERIAL_USART3) || defined(DEBUG_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART2) + #if defined(DEBUG_SERIAL_USART3) || defined(CONTROL_SERIAL_USART3) || defined(FEEDBACK_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) UART3_Init(); - huart = huart3; #endif - #if defined(CONTROL_SERIAL_USART2) || defined(CONTROL_SERIAL_USART3) - HAL_UART_Receive_DMA(&huart, (uint8_t *)&command, sizeof(command)); + #if defined(DEBUG_SERIAL_USART2) || defined(CONTROL_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) + HAL_UART_Receive_DMA(&huart2, (uint8_t *)rx_buffer_L, sizeof(rx_buffer_L)); #endif - #if defined(SIDEBOARD_SERIAL_USART2) - HAL_UART_Receive_DMA(&huart2, (uint8_t *)&Sideboard_Lnew, sizeof(Sideboard_Lnew)); - #endif - #if defined(SIDEBOARD_SERIAL_USART3) - HAL_UART_Receive_DMA(&huart3, (uint8_t *)&Sideboard_Rnew, sizeof(Sideboard_Rnew)); + #if defined(DEBUG_SERIAL_USART3) || defined(CONTROL_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) + HAL_UART_Receive_DMA(&huart3, (uint8_t *)rx_buffer_R, sizeof(rx_buffer_R)); #endif #ifdef CONTROL_ADC @@ -560,61 +568,57 @@ void poweroff(void) { void poweroffPressCheck(void) { #if defined(CONTROL_ADC) - if(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { - enable = 0; - uint16_t cnt_press = 0; - while(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { - HAL_Delay(10); - if (cnt_press++ == 5 * 100) { shortBeep(5); } - } - if (cnt_press >= 5 * 100) { // Check if press is more than 5 sec - HAL_Delay(300); - if (HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { // Double press: Adjust Max Current, Max Speed - while(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { HAL_Delay(10); } - longBeep(8); - updateCurSpdLim(); - shortBeep(5); - } else { // Long press: Calibrate ADC Limits - longBeep(16); - adcCalibLim(); - shortBeep(5); - } - } else { // Short press: power off - poweroff(); - } + if(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { + enable = 0; + uint16_t cnt_press = 0; + while(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { + HAL_Delay(10); + if (cnt_press++ == 5 * 100) { shortBeep(5); } } - #elif defined(VARIANT_TRANSPOTTER) - if(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { - enable = 0; - while(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { HAL_Delay(10); } - shortBeep(5); - HAL_Delay(300); - if (HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { - while(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { HAL_Delay(10); } - longBeep(5); - HAL_Delay(350); - poweroff(); - } else { - setDistance += 0.25; - if (setDistance > 2.6) { - setDistance = 0.5; - } - shortBeep(setDistance / 0.25); - saveValue = setDistance * 1000; - saveValue_valid = 1; + if (cnt_press >= 5 * 100) { // Check if press is more than 5 sec + HAL_Delay(300); + if (HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { // Double press: Adjust Max Current, Max Speed + while(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { HAL_Delay(10); } + longBeep(8); + updateCurSpdLim(); + shortBeep(5); + } else { // Long press: Calibrate ADC Limits + longBeep(16); + adcCalibLim(); + shortBeep(5); } + } else { // Short press: power off + poweroff(); } - #else + } + #elif defined(VARIANT_TRANSPOTTER) + if(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { + enable = 0; + while(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { HAL_Delay(10); } + shortBeep(5); + HAL_Delay(300); if (HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { - enable = 0; // disable motors - while (HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) {} // wait until button is released - if(__HAL_RCC_GET_FLAG(RCC_FLAG_SFTRST)) { // do not power off after software reset (from a programmer/debugger) - __HAL_RCC_CLEAR_RESET_FLAGS(); // clear reset flags - } else { - poweroff(); // release power-latch + while(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { HAL_Delay(10); } + longBeep(5); + HAL_Delay(350); + poweroff(); + } else { + setDistance += 0.25; + if (setDistance > 2.6) { + setDistance = 0.5; } + shortBeep(setDistance / 0.25); + saveValue = setDistance * 1000; + saveValue_valid = 1; } - #endif + } + #else + if (HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { + enable = 0; // disable motors + while (HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) {} // wait until button is released + poweroff(); // release power-latch + } + #endif } @@ -707,58 +711,18 @@ void readCommand(void) { #if defined(CONTROL_SERIAL_USART2) || defined(CONTROL_SERIAL_USART3) // Handle received data validity, timeout and fix out-of-sync if necessary - #ifdef CONTROL_IBUS - ibus_chksum = 0xFFFF - IBUS_LENGTH - IBUS_COMMAND; - for (uint8_t i = 0; i < (IBUS_NUM_CHANNELS * 2); i++) { - ibus_chksum -= command.channels[i]; + #ifdef CONTROL_IBUS + for (uint8_t i = 0; i < (IBUS_NUM_CHANNELS * 2); i+=2) { + ibus_captured_value[(i/2)] = CLAMP(command.channels[i] + (command.channels[i+1] << 8) - 1000, 0, INPUT_MAX); // 1000-2000 -> 0-1000 } - if (command.start == IBUS_LENGTH && command.type == IBUS_COMMAND && ibus_chksum == (uint16_t)((command.checksumh << 8) + command.checksuml)) { - if (timeoutFlagSerial) { // Check for previous timeout flag - if (timeoutCntSerial-- <= 0) // Timeout de-qualification - timeoutFlagSerial = 0; // Timeout flag cleared - } else { - for (uint8_t i = 0; i < (IBUS_NUM_CHANNELS * 2); i+=2) { - ibus_captured_value[(i/2)] = CLAMP(command.channels[i] + (command.channels[i+1] << 8) - 1000, 0, INPUT_MAX); // 1000-2000 -> 0-1000 - } - cmd1 = CLAMP((ibus_captured_value[0] - 500) * 2, INPUT_MIN, INPUT_MAX); - cmd2 = CLAMP((ibus_captured_value[1] - 500) * 2, INPUT_MIN, INPUT_MAX); - command.start = 0xFF; // Change the Start Frame for timeout detection in the next cycle - timeoutCntSerial = 0; // Reset the timeout counter - } - } else { - if (timeoutCntSerial++ >= SERIAL_TIMEOUT) { // Timeout qualification - timeoutFlagSerial = 1; // Timeout detected - timeoutCntSerial = SERIAL_TIMEOUT; // Limit timout counter value - } - // Most probably we are out-of-sync. Try to re-sync by reseting the DMA - if (command.start != IBUS_LENGTH && command.start != 0xFF && main_loop_counter % 2 == 0) { - HAL_UART_DMAStop(&huart); - HAL_UART_Receive_DMA(&huart, (uint8_t *)&command, sizeof(command)); - } - } + cmd1 = CLAMP((ibus_captured_value[0] - 500) * 2, INPUT_MIN, INPUT_MAX); + cmd2 = CLAMP((ibus_captured_value[1] - 500) * 2, INPUT_MIN, INPUT_MAX); #else - if (command.start == SERIAL_START_FRAME && command.checksum == (uint16_t)(command.start ^ command.steer ^ command.speed)) { - if (timeoutFlagSerial) { // Check for previous timeout flag - if (timeoutCntSerial-- <= 0) // Timeout de-qualification - timeoutFlagSerial = 0; // Timeout flag cleared - } else { - cmd1 = CLAMP((int16_t)command.steer, INPUT_MIN, INPUT_MAX); - cmd2 = CLAMP((int16_t)command.speed, INPUT_MIN, INPUT_MAX); - command.start = 0xFFFF; // Change the Start Frame for timeout detection in the next cycle - timeoutCntSerial = 0; // Reset the timeout counter - } - } else { - if (timeoutCntSerial++ >= SERIAL_TIMEOUT) { // Timeout qualification - timeoutFlagSerial = 1; // Timeout detected - timeoutCntSerial = SERIAL_TIMEOUT; // Limit timout counter value - } - // Most probably we are out-of-sync. Try to re-sync by reseting the DMA - if (command.start != SERIAL_START_FRAME && command.start != 0xFFFF && main_loop_counter % 2 == 0) { - HAL_UART_DMAStop(&huart); - HAL_UART_Receive_DMA(&huart, (uint8_t *)&command, sizeof(command)); - } - } - #endif + if (IN_RANGE(command.steer, INPUT_MIN, INPUT_MAX) && IN_RANGE(command.speed, INPUT_MIN, INPUT_MAX)) { + cmd1 = command.steer; + cmd2 = command.speed; + } + #endif if (timeoutFlagSerial) { // In case of timeout bring the system to a Safe State ctrlModReq = 0; // OPEN_MODE request. This will bring the motor power to 0 in a controlled way @@ -770,50 +734,17 @@ void readCommand(void) { timeout = 0; #endif - - #ifdef SIDEBOARD_SERIAL_USART2 - if (Sideboard_Lnew.start == SERIAL_START_FRAME && Sideboard_Lnew.checksum == (uint16_t)(Sideboard_Lnew.start ^ Sideboard_Lnew.roll ^ Sideboard_Lnew.pitch ^ Sideboard_Lnew.yaw ^ Sideboard_Lnew.sensors)) { - if (timeoutFlagSerial_L) { // Check for previous timeout flag - if (timeoutCntSerial_L-- <= 0) // Timeout de-qualification - timeoutFlagSerial_L = 0; // Timeout flag cleared - } else { - memcpy(&Sideboard_L, &Sideboard_Lnew, sizeof(Sideboard_L)); // Copy the new data - Sideboard_Lnew.start = 0xFFFF; // Change the Start Frame for timeout detection in the next cycle - timeoutCntSerial_L = 0; // Reset the timeout counter - } - } else { - if (timeoutCntSerial_L++ >= SERIAL_TIMEOUT) { // Timeout qualification - timeoutFlagSerial_L = 1; // Timeout detected - timeoutCntSerial_L = SERIAL_TIMEOUT; // Limit timout counter value - } - // Most probably we are out-of-sync. Try to re-sync by reseting the DMA - if (Sideboard_Lnew.start != SERIAL_START_FRAME && Sideboard_Lnew.start != 0xFFFF && main_loop_counter % 2 == 0) { - HAL_UART_DMAStop(&huart2); - HAL_UART_Receive_DMA(&huart2, (uint8_t *)&Sideboard_Lnew, sizeof(Sideboard_Lnew)); - } + #if defined(CONTROL_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) + if (timeoutCntSerial_L++ >= SERIAL_TIMEOUT) { // Timeout qualification + timeoutFlagSerial_L = 1; // Timeout detected + timeoutCntSerial_L = SERIAL_TIMEOUT; // Limit timout counter value } timeoutFlagSerial = timeoutFlagSerial_L; #endif - #ifdef SIDEBOARD_SERIAL_USART3 - if (Sideboard_Rnew.start == SERIAL_START_FRAME && Sideboard_Rnew.checksum == (uint16_t)(Sideboard_Rnew.start ^ Sideboard_Rnew.roll ^ Sideboard_Rnew.pitch ^ Sideboard_Rnew.yaw ^ Sideboard_Rnew.sensors)) { - if (timeoutFlagSerial_R) { // Check for previous timeout flag - if (timeoutCntSerial_R-- <= 0) // Timeout de-qualification - timeoutFlagSerial_R = 0; // Timeout flag cleared - } else { - memcpy(&Sideboard_R, &Sideboard_Rnew, sizeof(Sideboard_R)); // Copy the new data - Sideboard_Rnew.start = 0xFFFF; // Change the Start Frame for timeout detection in the next cycle - timeoutCntSerial_R = 0; // Reset the timeout counter - } - } else { - if (timeoutCntSerial_R++ >= SERIAL_TIMEOUT) { // Timeout qualification - timeoutFlagSerial_R = 1; // Timeout detected - timeoutCntSerial_R = SERIAL_TIMEOUT; // Limit timout counter value - } - // Most probably we are out-of-sync. Try to re-sync by reseting the DMA - if (Sideboard_Rnew.start != SERIAL_START_FRAME && Sideboard_Rnew.start != 0xFFFF && main_loop_counter % 2 == 0) { - HAL_UART_DMAStop(&huart3); - HAL_UART_Receive_DMA(&huart3, (uint8_t *)&Sideboard_Rnew, sizeof(Sideboard_Rnew)); - } + #if defined(CONTROL_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) + if (timeoutCntSerial_R++ >= SERIAL_TIMEOUT) { // Timeout qualification + timeoutFlagSerial_R = 1; // Timeout detected + timeoutCntSerial_R = SERIAL_TIMEOUT; // Limit timout counter value } timeoutFlagSerial = timeoutFlagSerial_R; #endif @@ -836,8 +767,261 @@ void readCommand(void) { #endif #endif +} +/* + * Check for new data received on USART2 with DMA: refactored function from https://github.com/MaJerle/stm32-usart-uart-dma-rx-tx + * - this function is called for every USART IDLE line detection, in the USART interrupt handler + */ +void usart2_rx_check(void) +{ + #if defined(DEBUG_SERIAL_USART2) || defined(CONTROL_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) + static uint32_t old_pos; + uint32_t pos; + pos = rx_buffer_L_len - __HAL_DMA_GET_COUNTER(huart2.hdmarx); // Calculate current position in buffer + #endif + + #if defined(DEBUG_SERIAL_USART2) + if (pos != old_pos) { // Check change in received data + if (pos > old_pos) { // "Linear" buffer mode: check if current position is over previous one + usart_process_debug(&rx_buffer_L[old_pos], pos - old_pos); // Process data + } else { // "Overflow" buffer mode + usart_process_debug(&rx_buffer_L[old_pos], rx_buffer_L_len - old_pos); // First Process data from the end of buffer + if (pos > 0) { // Check and continue with beginning of buffer + usart_process_debug(&rx_buffer_L[0], pos); // Process remaining data + } + } + } + #endif // DEBUG_SERIAL_USART2 + + #ifdef CONTROL_SERIAL_USART2 + uint8_t *ptr; + if (pos != old_pos) { // Check change in received data + ptr = (uint8_t *)&command_raw; // Initialize the pointer with command_raw address + if (pos > old_pos && (pos - old_pos) == command_len) { // "Linear" buffer mode: check if current position is over previous one AND data length equals expected length + memcpy(ptr, &rx_buffer_L[old_pos], command_len); // Copy data. This is possible only if command_raw is contiguous! (meaning all the structure members have the same size) + usart_process_command(&command_raw, &command, 2); // Process data + } else if ((rx_buffer_L_len - old_pos + pos) == command_len) { // "Overflow" buffer mode: check if data length equals expected length + memcpy(ptr, &rx_buffer_L[old_pos], rx_buffer_L_len - old_pos); // First copy data from the end of buffer + if (pos > 0) { // Check and continue with beginning of buffer + ptr += rx_buffer_L_len - old_pos; // Move to correct position in command_raw + memcpy(ptr, &rx_buffer_L[0], pos); // Copy remaining data + } + usart_process_command(&command_raw, &command, 2); // Process data + } + } + #endif // CONTROL_SERIAL_USART2 + + #ifdef SIDEBOARD_SERIAL_USART2 + uint8_t *ptr; + if (pos != old_pos) { // Check change in received data + ptr = (uint8_t *)&Sideboard_L_raw; // Initialize the pointer with Sideboard_raw address + if (pos > old_pos && (pos - old_pos) == Sideboard_L_len) { // "Linear" buffer mode: check if current position is over previous one AND data length equals expected length + memcpy(ptr, &rx_buffer_L[old_pos], Sideboard_L_len); // Copy data. This is possible only if Sideboard_raw is contiguous! (meaning all the structure members have the same size) + usart_process_sideboard(&Sideboard_L_raw, &Sideboard_L, 2); // Process data + } else if ((rx_buffer_L_len - old_pos + pos) == Sideboard_L_len) { // "Overflow" buffer mode: check if data length equals expected length + memcpy(ptr, &rx_buffer_L[old_pos], rx_buffer_L_len - old_pos); // First copy data from the end of buffer + if (pos > 0) { // Check and continue with beginning of buffer + ptr += rx_buffer_L_len - old_pos; // Move to correct position in Sideboard_raw + memcpy(ptr, &rx_buffer_L[0], pos); // Copy remaining data + } + usart_process_sideboard(&Sideboard_L_raw, &Sideboard_L, 2); // Process data + } + } + #endif // SIDEBOARD_SERIAL_USART2 + + #if defined(DEBUG_SERIAL_USART2) || defined(CONTROL_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) + old_pos = pos; // Update old position + if (old_pos == rx_buffer_L_len) { // Check and manually update if we reached end of buffer + old_pos = 0; + } + #endif +} + + +/* + * Check for new data received on USART3 with DMA: refactored function from https://github.com/MaJerle/stm32-usart-uart-dma-rx-tx + * - this function is called for every USART IDLE line detection, in the USART interrupt handler + */ +void usart3_rx_check(void) +{ + #if defined(DEBUG_SERIAL_USART3) || defined(CONTROL_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) + static uint32_t old_pos; + uint32_t pos; + pos = rx_buffer_R_len - __HAL_DMA_GET_COUNTER(huart3.hdmarx); // Calculate current position in buffer + #endif + + #if defined(DEBUG_SERIAL_USART3) + if (pos != old_pos) { // Check change in received data + if (pos > old_pos) { // "Linear" buffer mode: check if current position is over previous one + usart_process_debug(&rx_buffer_R[old_pos], pos - old_pos); // Process data + } else { // "Overflow" buffer mode + usart_process_debug(&rx_buffer_R[old_pos], rx_buffer_R_len - old_pos); // First Process data from the end of buffer + if (pos > 0) { // Check and continue with beginning of buffer + usart_process_debug(&rx_buffer_R[0], pos); // Process remaining data + } + } + } + #endif // DEBUG_SERIAL_USART3 + + #ifdef CONTROL_SERIAL_USART3 + uint8_t *ptr; + if (pos != old_pos) { // Check change in received data + ptr = (uint8_t *)&command_raw; // Initialize the pointer with command_raw address + if (pos > old_pos && (pos - old_pos) == command_len) { // "Linear" buffer mode: check if current position is over previous one AND data length equals expected length + memcpy(ptr, &rx_buffer_R[old_pos], command_len); // Copy data. This is possible only if command_raw is contiguous! (meaning all the structure members have the same size) + usart_process_command(&command_raw, &command, 3); // Process data + } else if ((rx_buffer_R_len - old_pos + pos) == command_len) { // "Overflow" buffer mode: check if data length equals expected length + memcpy(ptr, &rx_buffer_R[old_pos], rx_buffer_R_len - old_pos); // First copy data from the end of buffer + if (pos > 0) { // Check and continue with beginning of buffer + ptr += rx_buffer_R_len - old_pos; // Move to correct position in command_raw + memcpy(ptr, &rx_buffer_R[0], pos); // Copy remaining data + } + usart_process_command(&command_raw, &command, 3); // Process data + } + } + #endif // CONTROL_SERIAL_USART3 + + #ifdef SIDEBOARD_SERIAL_USART3 + uint8_t *ptr; + if (pos != old_pos) { // Check change in received data + ptr = (uint8_t *)&Sideboard_R_raw; // Initialize the pointer with Sideboard_raw address + if (pos > old_pos && (pos - old_pos) == Sideboard_R_len) { // "Linear" buffer mode: check if current position is over previous one AND data length equals expected length + memcpy(ptr, &rx_buffer_R[old_pos], Sideboard_R_len); // Copy data. This is possible only if Sideboard_raw is contiguous! (meaning all the structure members have the same size) + usart_process_sideboard(&Sideboard_R_raw, &Sideboard_R, 3); // Process data + } else if ((rx_buffer_R_len - old_pos + pos) == Sideboard_R_len) { // "Overflow" buffer mode: check if data length equals expected length + memcpy(ptr, &rx_buffer_R[old_pos], rx_buffer_R_len - old_pos); // First copy data from the end of buffer + if (pos > 0) { // Check and continue with beginning of buffer + ptr += rx_buffer_R_len - old_pos; // Move to correct position in Sideboard_raw + memcpy(ptr, &rx_buffer_R[0], pos); // Copy remaining data + } + usart_process_sideboard(&Sideboard_R_raw, &Sideboard_R, 3); // Process data + } + } + #endif // SIDEBOARD_SERIAL_USART3 + + #if defined(DEBUG_SERIAL_USART3) || defined(CONTROL_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) + old_pos = pos; // Update old position + if (old_pos == rx_buffer_R_len) { // Check and manually update if we reached end of buffer + old_pos = 0; + } + #endif +} + +/* + * Process Rx debug user command input + */ +#if defined(DEBUG_SERIAL_USART2) || defined(DEBUG_SERIAL_USART3) +void usart_process_debug(uint8_t *userCommand, uint32_t len) +{ + for (; len > 0; len--, userCommand++) { + if (*userCommand != '\n' && *userCommand != '\r') { // Do not accept 'new line' and 'carriage return' commands + consoleLog("-- Command received --\r\n"); + // handle_input(*userCommand); // -> Create this function to handle the user commands + } + } +} +#endif // SERIAL_DEBUG + +/* + * Process command Rx data + * - if the command_in data is valid (correct START_FRAME and checksum) copy the command_in to command_out + */ +#if defined(CONTROL_SERIAL_USART2) || defined(CONTROL_SERIAL_USART3) +void usart_process_command(SerialCommand *command_in, SerialCommand *command_out, uint8_t usart_idx) +{ + #ifdef CONTROL_IBUS + if (command_in->start == IBUS_LENGTH && command_in->type == IBUS_COMMAND) { + ibus_chksum = 0xFFFF - IBUS_LENGTH - IBUS_COMMAND; + for (uint8_t i = 0; i < (IBUS_NUM_CHANNELS * 2); i++) { + ibus_chksum -= command_in->channels[i]; + } + if (ibus_chksum == (uint16_t)((command_in->checksumh << 8) + command_in->checksuml)) { + *command_out = *command_in; + if (usart_idx == 2) { // Sideboard USART2 + #ifdef CONTROL_SERIAL_USART2 + timeoutCntSerial_L = 0; // Reset timeout counter + timeoutFlagSerial_L = 0; // Clear timeout flag + #endif + } else if (usart_idx == 3) { // Sideboard USART3 + #ifdef CONTROL_SERIAL_USART3 + timeoutCntSerial_R = 0; // Reset timeout counter + timeoutFlagSerial_R = 0; // Clear timeout flag + #endif + } + } + } + #else + uint16_t checksum; + if (command_in->start == SERIAL_START_FRAME) { + checksum = (uint16_t)(command_in->start ^ command_in->steer ^ command_in->speed); + if (command_in->checksum == checksum) { + *command_out = *command_in; + if (usart_idx == 2) { // Sideboard USART2 + #ifdef CONTROL_SERIAL_USART2 + timeoutCntSerial_L = 0; // Reset timeout counter + timeoutFlagSerial_L = 0; // Clear timeout flag + #endif + } else if (usart_idx == 3) { // Sideboard USART3 + #ifdef CONTROL_SERIAL_USART3 + timeoutCntSerial_R = 0; // Reset timeout counter + timeoutFlagSerial_R = 0; // Clear timeout flag + #endif + } + } + } + #endif +} +#endif + +/* + * Process Sideboard Rx data + * - if the Sideboard_in data is valid (correct START_FRAME and checksum) copy the Sideboard_in to Sideboard_out + */ +#if defined(SIDEBOARD_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART3) +void usart_process_sideboard(SerialSideboard *Sideboard_in, SerialSideboard *Sideboard_out, uint8_t usart_idx) +{ + uint16_t checksum; + if (Sideboard_in->start == SERIAL_START_FRAME) { + checksum = (uint16_t)(Sideboard_in->start ^ Sideboard_in->roll ^ Sideboard_in->pitch ^ Sideboard_in->yaw ^ Sideboard_in->sensors); + if (Sideboard_in->checksum == checksum) { + *Sideboard_out = *Sideboard_in; + if (usart_idx == 2) { // Sideboard USART2 + #ifdef SIDEBOARD_SERIAL_USART2 + timeoutCntSerial_L = 0; // Reset timeout counter + timeoutFlagSerial_L = 0; // Clear timeout flag + #endif + } else if (usart_idx == 3) { // Sideboard USART3 + #ifdef SIDEBOARD_SERIAL_USART3 + timeoutCntSerial_R = 0; // Reset timeout counter + timeoutFlagSerial_R = 0; // Clear timeout flag + #endif + } + } + } +} +#endif + + +/* + * UART User Error Callback + * - According to the STM documentation, when a DMA transfer error occurs during a DMA read or a write access, + * the faulty channel is automatically disabled through a hardware clear of its EN bit + * - For hoverboard applications, the UART communication can be unrealiable, disablind the DMA transfer + * - therefore the DMA needs to be re-started + */ +void HAL_UART_ErrorCallback(UART_HandleTypeDef *uartHandle) { + #if defined(DEBUG_SERIAL_USART2) || defined(CONTROL_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) + if(uartHandle->Instance == USART2) { + HAL_UART_Receive_DMA(uartHandle, (uint8_t *)rx_buffer_L, sizeof(rx_buffer_L)); + } + #endif + #if defined(DEBUG_SERIAL_USART3) || defined(CONTROL_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) + if(uartHandle->Instance == USART3) { + HAL_UART_Receive_DMA(uartHandle, (uint8_t *)rx_buffer_R, sizeof(rx_buffer_R)); + } + #endif } diff --git a/docs/STM32F103xC_datasheet.pdf b/docs/literature/[10]_STM32F103xC_datasheet.pdf similarity index 100% rename from docs/STM32F103xC_datasheet.pdf rename to docs/literature/[10]_STM32F103xC_datasheet.pdf diff --git a/docs/literature/[11]_GD32F103xx-Datasheet-Rev-2.7.pdf b/docs/literature/[11]_GD32F103xx-Datasheet-Rev-2.7.pdf new file mode 100644 index 0000000..2146f34 Binary files /dev/null and b/docs/literature/[11]_GD32F103xx-Datasheet-Rev-2.7.pdf differ diff --git a/docs/literature/[8] Sensorless-FOCWithFlux-Weakening.pdf b/docs/literature/[6] Sensorless-FOCWithFlux-Weakening.pdf similarity index 100% rename from docs/literature/[8] Sensorless-FOCWithFlux-Weakening.pdf rename to docs/literature/[6] Sensorless-FOCWithFlux-Weakening.pdf diff --git a/docs/literature/[9] Practical Field Weakening Current Vector Control.pdf b/docs/literature/[7] Practical Field Weakening Current Vector Control.pdf similarity index 100% rename from docs/literature/[9] Practical Field Weakening Current Vector Control.pdf rename to docs/literature/[7] Practical Field Weakening Current Vector Control.pdf diff --git a/docs/literature/[6] STM32 motor control SDK.pdf b/docs/literature/[8] STM32 motor control SDK.pdf similarity index 100% rename from docs/literature/[6] STM32 motor control SDK.pdf rename to docs/literature/[8] STM32 motor control SDK.pdf diff --git a/docs/literature/[7] STM32 REFERENCE Manual.pdf b/docs/literature/[9]_STM32_REFERENCE_Manual.pdf similarity index 100% rename from docs/literature/[7] STM32 REFERENCE Manual.pdf rename to docs/literature/[9]_STM32_REFERENCE_Manual.pdf