Major UART communication improvement

- the UART communication is improved based on UART Idle line detection interrupt
- an Rx ring buffer is used to manage the UART incoming data
- both Tx and Rx are efficiently handled using DMA

#45 #64 #65

Other:
- minor visual improvements
This commit is contained in:
EmanuelFeru 2020-06-21 23:14:46 +02:00
parent 85552b3e41
commit e46dff590f
17 changed files with 719 additions and 385 deletions

View File

@ -1,5 +1,5 @@
// ******************************************************************* // *******************************************************************
// Arduino Nano 3.3V example code // Arduino Nano 5V example code
// for https://github.com/EmanuelFeru/hoverboard-firmware-hack-FOC // for https://github.com/EmanuelFeru/hoverboard-firmware-hack-FOC
// //
// Copyright (C) 2019-2020 Emanuel FERU <aerdronix@gmail.com> // Copyright (C) 2019-2020 Emanuel FERU <aerdronix@gmail.com>
@ -12,14 +12,14 @@
// • The data packaging includes a Start Frame, checksum, and re-syncronization capability for reliable communication // • The data packaging includes a Start Frame, checksum, and re-syncronization capability for reliable communication
// //
// CONFIGURATION on the hoverboard side in config.h: // CONFIGURATION on the hoverboard side in config.h:
// • Option 1: Serial on Left Sensor cable (long wired cable) // • Option 1: Serial on Right Sensor cable (short wired cable) - recommended, since the USART3 pins are 5V tolerant.
// #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
// #define CONTROL_SERIAL_USART3 // #define CONTROL_SERIAL_USART3
// #define FEEDBACK_SERIAL_USART3 // #define FEEDBACK_SERIAL_USART3
// // #define DEBUG_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 ########################## // ########################## DEFINES ##########################

View File

@ -397,6 +397,7 @@
defined(FEEDBACK_SERIAL_USART3) || defined(CONTROL_SERIAL_USART3) || defined(DEBUG_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) 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_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_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 #endif
#if defined(FEEDBACK_SERIAL_USART2) || defined(CONTROL_SERIAL_USART2) || defined(DEBUG_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) #if defined(FEEDBACK_SERIAL_USART2) || defined(CONTROL_SERIAL_USART2) || defined(DEBUG_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2)
#ifndef USART2_BAUD #ifndef USART2_BAUD
@ -408,12 +409,6 @@
#define USART3_BAUD 38400 // UART3 baud rate (short wired cable) #define USART3_BAUD 38400 // UART3 baud rate (short wired cable)
#define USART3_WORDLENGTH UART_WORDLENGTH_8B // UART_WORDLENGTH_8B or UART_WORDLENGTH_9B #define USART3_WORDLENGTH UART_WORDLENGTH_8B // UART_WORDLENGTH_8B or UART_WORDLENGTH_9B
#endif #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 ############################ // ########################### UART SETIINGS ############################

View File

@ -152,6 +152,7 @@
#define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN3(a, b, c) MIN(a, MIN(b, c)) #define MIN3(a, b, c) MIN(a, MIN(b, c))
#define MAX3(a, b, c) MAX(a, MAX(b, c)) #define MAX3(a, b, c) MAX(a, MAX(b, c))
#define ARRAY_LEN(x) (uint32_t)(sizeof(x) / sizeof(*(x)))
typedef struct { typedef struct {
uint16_t dcr; uint16_t dcr;

View File

@ -56,7 +56,13 @@ void DebugMon_Handler(void);
void PendSV_Handler(void); void PendSV_Handler(void);
void SysTick_Handler(void); void SysTick_Handler(void);
void DMA1_Channel1_IRQHandler(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 DMA2_Channel4_5_IRQHandler(void);
void USART2_IRQHandler(void);
void USART3_IRQHandler(void);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -31,14 +31,14 @@
uint8_t channels[IBUS_NUM_CHANNELS*2]; uint8_t channels[IBUS_NUM_CHANNELS*2];
uint8_t checksuml; uint8_t checksuml;
uint8_t checksumh; uint8_t checksumh;
} Serialcommand; } SerialCommand;
#else #else
typedef struct{ typedef struct{
uint16_t start; uint16_t start;
int16_t steer; int16_t steer;
int16_t speed; int16_t speed;
uint16_t checksum; uint16_t checksum;
} Serialcommand; } SerialCommand;
#endif #endif
#endif #endif
#if defined(SIDEBOARD_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART3) #if defined(SIDEBOARD_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART3)
@ -73,6 +73,17 @@ void poweroffPressCheck(void);
// Read Command Function // Read Command Function
void readCommand(void); 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); int addDeadBand(int16_t u, int16_t deadBand, int16_t min, int16_t max);
// Sideboard functions // Sideboard functions

View File

@ -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-GD](https://github.com/EmanuelFeru/hoverboard-sideboard-hack-GD)
- [hoverboard-sideboard-hack-STM](https://github.com/EmanuelFeru/hoverboard-sideboard-hack-STM) - [hoverboard-sideboard-hack-STM](https://github.com/EmanuelFeru/hoverboard-sideboard-hack-STM)
--- ---
## Hardware ## Hardware
![mainboard_pinout](/docs/pictures/mainboard_pinout.png) ![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. 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.
Both USART2 & 3 can be used for UART and I2C, PA2&3 can be used as 12bit ADCs.
The reverse-engineered schematics of the mainboard can be found here: 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.
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.
For the reverse-engineered schematics of the mainboard, see [20150722_hoverboard_sch.pdf](/docs/20150722_hoverboard_sch.pdf)
---
## FOC Firmware
### Firmware Architecture ### 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 - **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 - **Diagnostics**: implements error detection such as unconnected Hall sensor, motor blocked, MOSFET defective
- **Control Manager**: manages the transitions between control modes (Voltage, Speed, Torque) - **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: In this firmware 3 control types are available:
- Commutation - Commutation
- SIN (Sinusoidal) - 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) ![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 ### Field Weakening / Phase Advance

View File

@ -30,12 +30,16 @@ void consoleScope(void) {
uart_buf[8] = CLAMP(ch_buf[7]+127, 0, 255); uart_buf[8] = CLAMP(ch_buf[7]+127, 0, 255);
uart_buf[9] = '\n'; uart_buf[9] = '\n';
if(UART_DMA_CHANNEL_TX->CNDTR == 0) { #ifdef DEBUG_SERIAL_USART2
UART_DMA_CHANNEL_TX->CCR &= ~DMA_CCR_EN; if(__HAL_DMA_GET_COUNTER(huart2.hdmatx) == 0) {
UART_DMA_CHANNEL_TX->CNDTR = 10; HAL_UART_Transmit_DMA(&huart2, (uint8_t *)uart_buf, strLength);
UART_DMA_CHANNEL_TX->CMAR = (uint32_t)uart_buf;
UART_DMA_CHANNEL_TX->CCR |= DMA_CCR_EN;
} }
#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 #endif
#if defined DEBUG_SERIAL_ASCII && (defined DEBUG_SERIAL_USART2 || defined DEBUG_SERIAL_USART3) #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, 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", "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]); 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) { #ifdef DEBUG_SERIAL_USART2
UART_DMA_CHANNEL_TX->CCR &= ~DMA_CCR_EN; if(__HAL_DMA_GET_COUNTER(huart2.hdmatx) == 0) {
UART_DMA_CHANNEL_TX->CNDTR = strLength; HAL_UART_Transmit_DMA(&huart2, (uint8_t *)uart_buf, strLength);
UART_DMA_CHANNEL_TX->CMAR = (uint32_t)uart_buf;
UART_DMA_CHANNEL_TX->CCR |= DMA_CCR_EN;
} }
#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 #endif
} }
void consoleLog(char *message) void consoleLog(char *message)
{ {
#if defined DEBUG_SERIAL_ASCII && (defined DEBUG_SERIAL_USART2 || defined DEBUG_SERIAL_USART3) #if defined DEBUG_SERIAL_ASCII && (defined DEBUG_SERIAL_USART2 || defined DEBUG_SERIAL_USART3)
if(UART_DMA_CHANNEL_TX->CNDTR == 0) { #ifdef DEBUG_SERIAL_USART2
UART_DMA_CHANNEL_TX->CCR &= ~DMA_CCR_EN; if(__HAL_DMA_GET_COUNTER(huart2.hdmatx) == 0) {
UART_DMA_CHANNEL_TX->CNDTR = strlen((char *)(uintptr_t)message); HAL_UART_Transmit_DMA(&huart2, (uint8_t *)message, strlen((char *)(uintptr_t)message));
UART_DMA_CHANNEL_TX->CMAR = (uint32_t)message;
UART_DMA_CHANNEL_TX->CCR |= DMA_CCR_EN;
} }
#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 #endif
} }

View File

@ -49,6 +49,9 @@ extern volatile adc_buf_t adc_buffer;
extern uint8_t LCDerrorFlag; extern uint8_t LCDerrorFlag;
#endif #endif
extern UART_HandleTypeDef huart2;
extern UART_HandleTypeDef huart3;
// Matlab defines - from auto-code generation // Matlab defines - from auto-code generation
//--------------- //---------------
extern P rtP_Left; /* Block parameters (auto storage) */ 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(6); // make 2 beeps indicating the motor enable
shortBeep(4); HAL_Delay(100); shortBeep(4); HAL_Delay(100);
enable = 1; // enable motors enable = 1; // enable motors
consoleLog("-- Motors enabled --\r\n");
} }
// ####### VARIANT_HOVERCAR ####### // ####### VARIANT_HOVERCAR #######
@ -418,25 +422,21 @@ int main(void) {
Feedback.boardTemp = (int16_t)board_temp_deg_c; Feedback.boardTemp = (int16_t)board_temp_deg_c;
#if defined(FEEDBACK_SERIAL_USART2) #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.cmdLed = (uint16_t)sideboard_leds_L;
Feedback.checksum = (uint16_t)(Feedback.start ^ Feedback.cmd1 ^ Feedback.cmd2 ^ Feedback.speedR_meas ^ Feedback.speedL_meas Feedback.checksum = (uint16_t)(Feedback.start ^ Feedback.cmd1 ^ Feedback.cmd2 ^ Feedback.speedR_meas ^ Feedback.speedL_meas
^ Feedback.batVoltage ^ Feedback.boardTemp ^ Feedback.cmdLed); ^ Feedback.batVoltage ^ Feedback.boardTemp ^ Feedback.cmdLed);
DMA1_Channel7->CCR &= ~DMA_CCR_EN;
DMA1_Channel7->CNDTR = sizeof(Feedback); HAL_UART_Transmit_DMA(&huart2, (uint8_t *)&Feedback, sizeof(Feedback));
DMA1_Channel7->CMAR = (uint32_t)&Feedback;
DMA1_Channel7->CCR |= DMA_CCR_EN;
} }
#endif #endif
#if defined(FEEDBACK_SERIAL_USART3) #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.cmdLed = (uint16_t)sideboard_leds_R;
Feedback.checksum = (uint16_t)(Feedback.start ^ Feedback.cmd1 ^ Feedback.cmd2 ^ Feedback.speedR_meas ^ Feedback.speedL_meas Feedback.checksum = (uint16_t)(Feedback.start ^ Feedback.cmd1 ^ Feedback.cmd2 ^ Feedback.speedR_meas ^ Feedback.speedL_meas
^ Feedback.batVoltage ^ Feedback.boardTemp ^ Feedback.cmdLed); ^ Feedback.batVoltage ^ Feedback.boardTemp ^ Feedback.cmdLed);
DMA1_Channel2->CCR &= ~DMA_CCR_EN;
DMA1_Channel2->CNDTR = sizeof(Feedback); HAL_UART_Transmit_DMA(&huart3, (uint8_t *)&Feedback, sizeof(Feedback));
DMA1_Channel2->CMAR = (uint32_t)&Feedback;
DMA1_Channel2->CCR |= DMA_CCR_EN;
} }
#endif #endif
} }

View File

@ -37,6 +37,7 @@ pb10 usart3 dma1 channel2/3
#include "defines.h" #include "defines.h"
#include "config.h" #include "config.h"
#include "setup.h"
TIM_HandleTypeDef htim_right; TIM_HandleTypeDef htim_right;
TIM_HandleTypeDef htim_left; TIM_HandleTypeDef htim_left;
@ -53,178 +54,227 @@ DMA_HandleTypeDef hdma_usart3_tx;
volatile adc_buf_t adc_buffer; volatile adc_buf_t adc_buffer;
#if defined(CONTROL_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) || \ #if defined(DEBUG_SERIAL_USART2) || defined(CONTROL_SERIAL_USART2) || defined(FEEDBACK_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2)
defined(FEEDBACK_SERIAL_USAR2) || defined(DEBUG_SERIAL_USART2) /* USART2 init function */
void UART2_Init(void) { void UART2_Init(void)
{
/* The code below is commented out - otwerwise Serial Receive does not work */ /* DMA controller clock enable */
// #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
__HAL_RCC_DMA1_CLK_ENABLE(); __HAL_RCC_DMA1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_USART2_CLK_ENABLE(); /* DMA1_Channel6_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel6_IRQn, 0, 0);
huart2.Instance = USART2; HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn);
huart2.Init.BaudRate = USART2_BAUD; /* DMA1_Channel7_IRQn interrupt configuration */
huart2.Init.WordLength = USART2_WORDLENGTH; HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 0, 0);
huart2.Init.StopBits = UART_STOPBITS_1; HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart2.Instance = USART2;
huart2.Init.OverSampling = UART_OVERSAMPLING_16; huart2.Init.BaudRate = USART2_BAUD;
#if defined(CONTROL_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) huart2.Init.WordLength = USART2_WORDLENGTH;
huart2.Init.Mode = UART_MODE_TX_RX; huart2.Init.StopBits = UART_STOPBITS_1;
#elif defined(FEEDBACK_SERIAL_USART2) || defined(DEBUG_SERIAL_USART2) huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX; huart2.Init.Mode = UART_MODE_TX_RX;
#endif huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart2); HAL_UART_Init(&huart2);
}
#endif
#if defined(FEEDBACK_SERIAL_USART2) || defined(DEBUG_SERIAL_USART2) #if defined(DEBUG_SERIAL_USART3) || defined(CONTROL_SERIAL_USART3) || defined(FEEDBACK_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3)
USART2->CR3 |= USART_CR3_DMAT; // | USART_CR3_DMAR | USART_CR3_OVRDIS; /* USART3 init function */
#endif void UART3_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct; /* DMA interrupt init */
GPIO_InitStruct.Pin = GPIO_PIN_2; /* DMA1_Channel2_IRQn interrupt configuration */
GPIO_InitStruct.Pull = GPIO_PULLUP; //GPIO_NOPULL; HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; /* DMA1_Channel3_IRQn interrupt configuration */
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 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) void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
GPIO_InitStruct.Pin = GPIO_PIN_3; {
GPIO_InitStruct.Mode = GPIO_MODE_INPUT; //GPIO_MODE_AF_PP; 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); HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* Peripheral DMA init*/ GPIO_InitStruct.Pin = GPIO_PIN_3;
hdma_usart2_rx.Instance = DMA1_Channel6; GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; GPIO_InitStruct.Pull = GPIO_PULLUP;
hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE;
/* 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.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart2_rx.Init.Mode = DMA_CIRCULAR; //DMA_NORMAL; hdma_usart2_rx.Init.Mode = DMA_CIRCULAR;
hdma_usart2_rx.Init.Priority = DMA_PRIORITY_LOW; hdma_usart2_rx.Init.Priority = DMA_PRIORITY_LOW;
HAL_DMA_Init(&hdma_usart2_rx); HAL_DMA_Init(&hdma_usart2_rx);
__HAL_LINKDMA(&huart2, hdmarx, hdma_usart2_rx); __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart2_rx);
#endif
hdma_usart2_tx.Instance = DMA1_Channel7; /* USART2_TX Init */
hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_usart2_tx.Instance = DMA1_Channel7;
hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart2_tx.Init.Mode = DMA_NORMAL; hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW; hdma_usart2_tx.Init.Mode = DMA_NORMAL;
HAL_DMA_Init(&hdma_usart2_tx); 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) /* USART2 interrupt Init */
__HAL_LINKDMA(&huart2, hdmatx, hdma_usart2_tx); HAL_NVIC_SetPriority(USART2_IRQn, 0, 0);
#endif HAL_NVIC_EnableIRQ(USART2_IRQn);
#if defined(FEEDBACK_SERIAL_USART2) || defined(DEBUG_SERIAL_USART2) /* USER CODE BEGIN USART2_MspInit 1 */
DMA1_Channel7->CPAR = (uint32_t) & (USART2->DR); __HAL_UART_ENABLE_IT (uartHandle, UART_IT_IDLE); // Enable the USART IDLE line detection interrupt
DMA1_Channel7->CNDTR = 0; /* USER CODE END USART2_MspInit 1 */
DMA1->IFCR = DMA_IFCR_CTCIF7 | DMA_IFCR_CHTIF7 | DMA_IFCR_CGIF7; }
#endif else if(uartHandle->Instance==USART3)
{
/* USER CODE BEGIN USART3_MspInit 0 */
} /* USER CODE END USART3_MspInit 0 */
#endif /* USART3 clock enable */
__HAL_RCC_USART3_CLK_ENABLE();
#if defined(CONTROL_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) || \
defined(FEEDBACK_SERIAL_USART3) || defined(DEBUG_SERIAL_USART3) __HAL_RCC_GPIOB_CLK_ENABLE();
void UART3_Init(void) { /**USART3 GPIO Configuration
PB10 ------> USART3_TX
/* The code below is commented out - otwerwise Serial Receive does not work */ PB11 ------> USART3_RX
// #if defined(CONTROL_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) */
// /* DMA1_Channel3_IRQn interrupt configuration */ GPIO_InitStruct.Pin = GPIO_PIN_10;
// HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 5, 3); GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
// HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn); GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
// /* 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;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Peripheral DMA init*/ GPIO_InitStruct.Pin = GPIO_PIN_11;
hdma_usart3_rx.Instance = DMA1_Channel3; GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
hdma_usart3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; GPIO_InitStruct.Pull = GPIO_PULLUP;
hdma_usart3_rx.Init.PeriphInc = DMA_PINC_DISABLE; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
hdma_usart3_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; /* USART3 DMA Init */
hdma_usart3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; /* USART3_RX Init */
hdma_usart3_rx.Init.Mode = DMA_CIRCULAR; //DMA_NORMAL; hdma_usart3_rx.Instance = DMA1_Channel3;
hdma_usart3_rx.Init.Priority = DMA_PRIORITY_LOW; 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_DMA_Init(&hdma_usart3_rx);
__HAL_LINKDMA(&huart3, hdmarx, hdma_usart3_rx); __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart3_rx);
#endif
hdma_usart3_tx.Instance = DMA1_Channel2; /* USART3_TX Init */
hdma_usart3_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_usart3_tx.Instance = DMA1_Channel2;
hdma_usart3_tx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart3_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_usart3_tx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart3_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart3_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart3_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart3_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart3_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart3_tx.Init.Mode = DMA_NORMAL; hdma_usart3_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart3_tx.Init.Priority = DMA_PRIORITY_LOW; hdma_usart3_tx.Init.Mode = DMA_NORMAL;
HAL_DMA_Init(&hdma_usart3_tx); 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) /* USART3 interrupt Init */
__HAL_LINKDMA(&huart3, hdmatx, hdma_usart3_tx); HAL_NVIC_SetPriority(USART3_IRQn, 0, 0);
#endif HAL_NVIC_EnableIRQ(USART3_IRQn);
#if defined(FEEDBACK_SERIAL_USART3) || defined(DEBUG_SERIAL_USART3) /* USER CODE BEGIN USART3_MspInit 1 */
DMA1_Channel2->CPAR = (uint32_t) & (USART3->DR); __HAL_UART_ENABLE_IT (uartHandle, UART_IT_IDLE); // Enable the USART IDLE line detection interrupt
DMA1_Channel2->CNDTR = 0; /* USER CODE END USART3_MspInit 1 */
DMA1->IFCR = DMA_IFCR_CTCIF2 | DMA_IFCR_CHTIF2 | DMA_IFCR_CGIF2; }
#endif
} }
#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_rx;
DMA_HandleTypeDef hdma_i2c2_tx; DMA_HandleTypeDef hdma_i2c2_tx;

View File

@ -36,6 +36,7 @@
#include "stm32f1xx_it.h" #include "stm32f1xx_it.h"
#include "defines.h" #include "defines.h"
#include "config.h" #include "config.h"
#include "util.h"
extern DMA_HandleTypeDef hdma_i2c2_rx; extern DMA_HandleTypeDef hdma_i2c2_rx;
extern DMA_HandleTypeDef hdma_i2c2_tx; 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_rx;
extern DMA_HandleTypeDef hdma_usart2_tx; extern DMA_HandleTypeDef hdma_usart2_tx;
extern DMA_HandleTypeDef hdma_usart3_rx;
extern DMA_HandleTypeDef hdma_usart3_tx;
/* USER CODE BEGIN 0 */ /* USER CODE BEGIN 0 */
extern UART_HandleTypeDef huart2;
extern UART_HandleTypeDef huart3;
/* USER CODE END 0 */ /* USER CODE END 0 */
/* External variables --------------------------------------------------------*/ /* External variables --------------------------------------------------------*/
@ -250,7 +254,7 @@ void EXTI2_IRQHandler(void)
} }
#endif #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) void DMA1_Channel6_IRQHandler(void)
{ {
/* USER CODE BEGIN DMA1_Channel4_IRQn 0 */ /* USER CODE BEGIN DMA1_Channel4_IRQn 0 */
@ -277,6 +281,74 @@ void DMA1_Channel7_IRQHandler(void)
} }
#endif #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 */ /* STM32F1xx Peripheral Interrupt Handlers */
/* Add here the Interrupt Handlers for the used peripherals. */ /* Add here the Interrupt Handlers for the used peripherals. */

View File

@ -41,12 +41,8 @@
//------------------------------------------------------------------------ //------------------------------------------------------------------------
extern volatile adc_buf_t adc_buffer; extern volatile adc_buf_t adc_buffer;
extern I2C_HandleTypeDef hi2c2; extern I2C_HandleTypeDef hi2c2;
#if defined(CONTROL_SERIAL_USART2) || defined(FEEDBACK_SERIAL_USART2) || defined(DEBUG_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2) \ extern UART_HandleTypeDef huart2;
|| defined(CONTROL_SERIAL_USART3) || defined(FEEDBACK_SERIAL_USART3) || defined(DEBUG_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3) extern UART_HandleTypeDef huart3;
extern UART_HandleTypeDef huart2;
extern UART_HandleTypeDef huart3;
static UART_HandleTypeDef huart;
#endif
extern int16_t batVoltage; extern int16_t batVoltage;
extern uint8_t backwardDrive; 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 ctrlModReqRaw = CTRL_MOD_REQ;
uint8_t ctrlModReq = CTRL_MOD_REQ; // Final control mode request 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) #if defined(SIDEBOARD_SERIAL_USART2)
SerialSideboard Sideboard_L; SerialSideboard Sideboard_L;
static SerialSideboard Sideboard_Lnew; SerialSideboard Sideboard_L_raw;
static uint8_t timeoutFlagSerial_L = 0; static uint32_t Sideboard_L_len = sizeof(Sideboard_L);
static int16_t timeoutCntSerial_L = 0; #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 #endif
#if defined(SIDEBOARD_SERIAL_USART3) #if defined(SIDEBOARD_SERIAL_USART3)
SerialSideboard Sideboard_R; SerialSideboard Sideboard_R;
static SerialSideboard Sideboard_Rnew; SerialSideboard Sideboard_R_raw;
static uint8_t timeoutFlagSerial_R = 0; static uint32_t Sideboard_R_len = sizeof(Sideboard_R);
static int16_t timeoutCntSerial_R = 0; #endif
#endif
#if !defined(VARIANT_HOVERBOARD) && (defined(SIDEBOARD_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART3)) #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 sensor1_prev; // holds the previous sensor1 state
static uint8_t sensor2_prev; // holds the previous sensor2 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 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 static uint8_t sensor2_index; // holds the press index number for sensor2, when used as a button
#endif #endif
#if defined(DEBUG_I2C_LCD) || defined(SUPPORT_LCD) #if defined(DEBUG_I2C_LCD) || defined(SUPPORT_LCD)
@ -158,8 +170,9 @@ static int16_t timeoutCntADC = 0; // Timeout counter for ADC Protection
#endif #endif
#if defined(CONTROL_SERIAL_USART2) || defined(CONTROL_SERIAL_USART3) #if defined(CONTROL_SERIAL_USART2) || defined(CONTROL_SERIAL_USART3)
static int16_t timeoutCntSerial = 0; // Timeout counter for Rx Serial command static SerialCommand command;
static volatile Serialcommand command; static SerialCommand command_raw;
static uint32_t command_len = sizeof(command);
#ifdef CONTROL_IBUS #ifdef CONTROL_IBUS
static uint16_t ibus_chksum; static uint16_t ibus_chksum;
static uint16_t ibus_captured_value[IBUS_NUM_CHANNELS]; static uint16_t ibus_captured_value[IBUS_NUM_CHANNELS];
@ -253,22 +266,17 @@ void Input_Init(void) {
Nunchuk_Init(); Nunchuk_Init();
#endif #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(); UART2_Init();
huart = huart2;
#endif #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(); UART3_Init();
huart = huart3;
#endif #endif
#if defined(CONTROL_SERIAL_USART2) || defined(CONTROL_SERIAL_USART3) #if defined(DEBUG_SERIAL_USART2) || defined(CONTROL_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2)
HAL_UART_Receive_DMA(&huart, (uint8_t *)&command, sizeof(command)); HAL_UART_Receive_DMA(&huart2, (uint8_t *)rx_buffer_L, sizeof(rx_buffer_L));
#endif #endif
#if defined(SIDEBOARD_SERIAL_USART2) #if defined(DEBUG_SERIAL_USART3) || defined(CONTROL_SERIAL_USART3) || defined(SIDEBOARD_SERIAL_USART3)
HAL_UART_Receive_DMA(&huart2, (uint8_t *)&Sideboard_Lnew, sizeof(Sideboard_Lnew)); HAL_UART_Receive_DMA(&huart3, (uint8_t *)rx_buffer_R, sizeof(rx_buffer_R));
#endif
#if defined(SIDEBOARD_SERIAL_USART3)
HAL_UART_Receive_DMA(&huart3, (uint8_t *)&Sideboard_Rnew, sizeof(Sideboard_Rnew));
#endif #endif
#ifdef CONTROL_ADC #ifdef CONTROL_ADC
@ -560,61 +568,57 @@ void poweroff(void) {
void poweroffPressCheck(void) { void poweroffPressCheck(void) {
#if defined(CONTROL_ADC) #if defined(CONTROL_ADC)
if(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { if(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) {
enable = 0; enable = 0;
uint16_t cnt_press = 0; uint16_t cnt_press = 0;
while(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { while(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) {
HAL_Delay(10); HAL_Delay(10);
if (cnt_press++ == 5 * 100) { shortBeep(5); } 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();
}
} }
#elif defined(VARIANT_TRANSPOTTER) if (cnt_press >= 5 * 100) { // Check if press is more than 5 sec
if(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { HAL_Delay(300);
enable = 0; 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); } while(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { HAL_Delay(10); }
shortBeep(5); longBeep(8);
HAL_Delay(300); updateCurSpdLim();
if (HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { shortBeep(5);
while(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { HAL_Delay(10); } } else { // Long press: Calibrate ADC Limits
longBeep(5); longBeep(16);
HAL_Delay(350); adcCalibLim();
poweroff(); shortBeep(5);
} else {
setDistance += 0.25;
if (setDistance > 2.6) {
setDistance = 0.5;
}
shortBeep(setDistance / 0.25);
saveValue = setDistance * 1000;
saveValue_valid = 1;
} }
} 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)) { if (HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) {
enable = 0; // disable motors while(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { HAL_Delay(10); }
while (HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) {} // wait until button is released longBeep(5);
if(__HAL_RCC_GET_FLAG(RCC_FLAG_SFTRST)) { // do not power off after software reset (from a programmer/debugger) HAL_Delay(350);
__HAL_RCC_CLEAR_RESET_FLAGS(); // clear reset flags poweroff();
} else { } else {
poweroff(); // release power-latch 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) #if defined(CONTROL_SERIAL_USART2) || defined(CONTROL_SERIAL_USART3)
// Handle received data validity, timeout and fix out-of-sync if necessary // Handle received data validity, timeout and fix out-of-sync if necessary
#ifdef CONTROL_IBUS #ifdef CONTROL_IBUS
ibus_chksum = 0xFFFF - IBUS_LENGTH - IBUS_COMMAND; for (uint8_t i = 0; i < (IBUS_NUM_CHANNELS * 2); i+=2) {
for (uint8_t i = 0; i < (IBUS_NUM_CHANNELS * 2); i++) { ibus_captured_value[(i/2)] = CLAMP(command.channels[i] + (command.channels[i+1] << 8) - 1000, 0, INPUT_MAX); // 1000-2000 -> 0-1000
ibus_chksum -= command.channels[i];
} }
if (command.start == IBUS_LENGTH && command.type == IBUS_COMMAND && ibus_chksum == (uint16_t)((command.checksumh << 8) + command.checksuml)) { cmd1 = CLAMP((ibus_captured_value[0] - 500) * 2, INPUT_MIN, INPUT_MAX);
if (timeoutFlagSerial) { // Check for previous timeout flag cmd2 = CLAMP((ibus_captured_value[1] - 500) * 2, INPUT_MIN, INPUT_MAX);
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));
}
}
#else #else
if (command.start == SERIAL_START_FRAME && command.checksum == (uint16_t)(command.start ^ command.steer ^ command.speed)) { if (IN_RANGE(command.steer, INPUT_MIN, INPUT_MAX) && IN_RANGE(command.speed, INPUT_MIN, INPUT_MAX)) {
if (timeoutFlagSerial) { // Check for previous timeout flag cmd1 = command.steer;
if (timeoutCntSerial-- <= 0) // Timeout de-qualification cmd2 = command.speed;
timeoutFlagSerial = 0; // Timeout flag cleared }
} else { #endif
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 (timeoutFlagSerial) { // In case of timeout bring the system to a Safe State 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 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; timeout = 0;
#endif #endif
#if defined(CONTROL_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2)
#ifdef SIDEBOARD_SERIAL_USART2 if (timeoutCntSerial_L++ >= SERIAL_TIMEOUT) { // Timeout qualification
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)) { timeoutFlagSerial_L = 1; // Timeout detected
if (timeoutFlagSerial_L) { // Check for previous timeout flag timeoutCntSerial_L = SERIAL_TIMEOUT; // Limit timout counter value
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));
}
} }
timeoutFlagSerial = timeoutFlagSerial_L; timeoutFlagSerial = timeoutFlagSerial_L;
#endif #endif
#ifdef SIDEBOARD_SERIAL_USART3 #if defined(CONTROL_SERIAL_USART3) || defined(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 (timeoutCntSerial_R++ >= SERIAL_TIMEOUT) { // Timeout qualification
if (timeoutFlagSerial_R) { // Check for previous timeout flag timeoutFlagSerial_R = 1; // Timeout detected
if (timeoutCntSerial_R-- <= 0) // Timeout de-qualification timeoutCntSerial_R = SERIAL_TIMEOUT; // Limit timout counter value
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));
}
} }
timeoutFlagSerial = timeoutFlagSerial_R; timeoutFlagSerial = timeoutFlagSerial_R;
#endif #endif
@ -836,8 +767,261 @@ void readCommand(void) {
#endif #endif
#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
} }

Binary file not shown.