diff --git a/Firmware/carteHRI.uvoptx b/Firmware/carteHRI.uvoptx
index 06161cb..fc80484 100644
--- a/Firmware/carteHRI.uvoptx
+++ b/Firmware/carteHRI.uvoptx
@@ -1,749 +1,762 @@
1.0
### uVision Project, (C) Keil Software
*.c
*.s*; *.src; *.a*
*.obj
*.lib
*.txt; *.h; *.inc
*.plm
*.cpp
0
0
0
Target 1
0x4
ARM-ADS
168000000
1
1
0
1
0
1
65535
0
0
0
79
66
8
.\lst\
1
1
1
0
1
1
0
1
0
0
0
0
1
1
1
1
1
1
1
0
0
1
0
1
18
0
User Manual (MCBSTM32F400)
C:\Keil_v5\ARM\PACK\Keil\STM32F4xx_DFP\2.5.0\MDK\Boards\Keil\MCBSTM32F400\Documentation\mcbstm32f200.chm
1
Schematics (MCBSTM32F400)
C:\Keil_v5\ARM\PACK\Keil\STM32F4xx_DFP\2.5.0\MDK\Boards\Keil\MCBSTM32F400\Documentation\mcbstm32f400-schematics.pdf
2
Getting Started (STM32F4-Discovery)
C:\Keil_v5\ARM\PACK\Keil\STM32F4xx_DFP\2.5.0\MDK\Boards\ST\STM32F4-Discovery\Documentation\DM00037368.pdf
3
User Manual (STM32F4-Discovery)
C:\Keil_v5\ARM\PACK\Keil\STM32F4xx_DFP\2.5.0\MDK\Boards\ST\STM32F4-Discovery\Documentation\DM00039084.pdf
4
Bill of Materials (STM32F4-Discovery)
C:\Keil_v5\ARM\PACK\Keil\STM32F4xx_DFP\2.5.0\MDK\Boards\ST\STM32F4-Discovery\Documentation\stm32f4discovery_bom.zip
5
Gerber Files (STM32F4-Discovery)
C:\Keil_v5\ARM\PACK\Keil\STM32F4xx_DFP\2.5.0\MDK\Boards\ST\STM32F4-Discovery\Documentation\stm32f4discovery_gerber.zip
6
Schematics (STM32F4-Discovery)
C:\Keil_v5\ARM\PACK\Keil\STM32F4xx_DFP\2.5.0\MDK\Boards\ST\STM32F4-Discovery\Documentation\stm32f4discovery_sch.zip
7
MCBSTM32F400 Evaluation Board Web Page (MCBSTM32F400)
http://www.keil.com/mcbstm32f400/
8
STM32F4-Discovery Web Page (STM32F4-Discovery)
http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1199/PF252419
0
1
1
1
1
1
1
1
1
1
0
1
1
1
0
1
1
1
1
0
0
11
STLink\ST-LINKIII-KEIL_SWO.dll
0
ARMRTXEVENTFLAGS
-L50 -Z18 -C0 -M0 -T0
0
DLGDARM
(1010=-1,-1,-1,-1,0)(1007=-1,-1,-1,-1,0)(1008=-1,-1,-1,-1,0)(1009=-1,-1,-1,-1,0)(1012=-1,-1,-1,-1,0)
0
DLGTARM
(1010=-1,-1,-1,-1,0)(1007=-1,-1,-1,-1,0)(1008=-1,-1,-1,-1,0)(1009=-1,-1,-1,-1,0)(1012=-1,-1,-1,-1,0)
0
ARMDBGFLAGS
-T0
0
DLGUARM
(105=-1,-1,-1,-1,0)
0
ST-LINKIII-KEIL_SWO
- -U303030303030303030303031 -I0 -O8398 -S1 -C0 -A0 -N00("ARM CoreSight SW-DP") -D00(2BA01477) -L00(0) -TO19 -TC168000000 -TP21 -TDS8053 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -FO15 -FD20000000 -FC800 -FN1 -FF0STM32F4xx_1024.FLM -FS08000000 -FL0100000 -FP0($$Device:STM32F407VG$CMSIS\Flash\STM32F4xx_1024.FLM)
+ -U303030303030303030303031 -O8398 -S1 -C0 -A0 -N00("ARM CoreSight SW-DP") -D00(2BA01477) -L00(0) -TO19 -TC168000000 -TP21 -TDS8053 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -FO15 -FD20000000 -FC800 -FN1 -FF0STM32F4xx_1024.FLM -FS08000000 -FL0100000 -FP0($$Device:STM32F407VG$CMSIS\Flash\STM32F4xx_1024.FLM)
0
UL2CM3
UL2CM3(-S0 -C0 -P0 -FD20000000 -FC1000 -FN1 -FF0STM32F4xx_1024 -FS08000000 -FL0100000 -FP0($$Device:STM32F407VG$Flash\STM32F4xx_1024.FLM))
0
1
- statusReg,0x0A
+ uart_txBuffer[0]
1
1
- ctrl_currentPid,0x0A
+ uart_txBuffer[1]
2
1
- adc_currentSensOffset,0x0A
+ uart_currentTxBufferToWriteTo
3
1
- ctrl_motorTorque_Nm_c
+ testVar
4
1
- ctrl_positionPid
+ uart_txBufferIndex
0
2
motorCurrentDebug
1
2
motorTargetCurrentDebug
2
2
ctrl_motorTorque_mNm_c
3
2
motorTorque_mNm_dbg
4
2
motorTorque_mNm
5
2
nCycles
6
2
motorPosCod,0x0A
7
2
CurrentSensOffset,0x0A
8
2
motorCurrent_mA_mean
9
2
motorCurrent_mA
10
2
ADCValuesBuffer,0x0A
11
2
motorCurrent_mA
12
2
motorCurrentSum
13
2
debugVar01,0x0A
14
2
adcValues1,0x0A
15
2
motorCurrent_mA
0
0
1
1
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
STM32_files
1
0
0
0
1
1
1
0
0
0
0
.\src\system_stm32f4xx.c
system_stm32f4xx.c
0
0
1
2
2
0
0
0
0
.\startup_stm32f4xx.s
startup_stm32f4xx.s
0
0
SRC
1
0
0
0
2
3
1
0
0
0
0
.\src\main.c
main.c
0
0
2
4
1
0
0
0
0
.\src\communication.c
communication.c
0
0
2
5
1
0
0
0
0
.\src\controller.c
controller.c
0
0
STM32_libs
1
0
0
0
3
6
1
0
0
0
0
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32F4xx_StdPeriph_Driver\src\stm32f4xx_gpio.c
stm32f4xx_gpio.c
0
0
3
7
1
0
0
0
0
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32F4xx_StdPeriph_Driver\src\stm32f4xx_rcc.c
stm32f4xx_rcc.c
0
0
3
8
1
0
0
0
0
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32F4xx_StdPeriph_Driver\src\stm32f4xx_tim.c
stm32f4xx_tim.c
0
0
3
9
1
0
0
0
0
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32F4xx_StdPeriph_Driver\src\misc.c
misc.c
0
0
3
10
1
0
0
0
0
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32F4xx_StdPeriph_Driver\src\stm32f4xx_exti.c
stm32f4xx_exti.c
0
0
3
11
1
0
0
0
0
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32F4xx_StdPeriph_Driver\src\stm32f4xx_syscfg.c
stm32f4xx_syscfg.c
0
0
3
12
1
0
0
0
0
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32F4xx_StdPeriph_Driver\src\stm32f4xx_adc.c
stm32f4xx_adc.c
0
0
3
13
1
0
0
0
0
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32F4xx_StdPeriph_Driver\src\stm32f4xx_dac.c
stm32f4xx_dac.c
0
0
3
14
1
0
0
0
0
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32F4xx_StdPeriph_Driver\src\stm32f4xx_dma.c
stm32f4xx_dma.c
0
0
3
15
1
0
0
0
0
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32F4xx_StdPeriph_Driver\src\stm32f4xx_usart.c
stm32f4xx_usart.c
0
0
3
16
4
0
0
0
0
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\CMSIS\Lib\ARM\arm_cortexM4lf_math.lib
arm_cortexM4lf_math.lib
0
0
SRC_drivers
1
0
0
0
4
17
1
0
0
0
0
.\src\drivers\adc.c
adc.c
0
0
4
18
1
0
0
0
0
.\src\drivers\callback_timers.c
callback_timers.c
0
0
4
19
1
0
0
0
0
.\src\drivers\dac.c
dac.c
0
0
4
20
1
0
0
0
0
.\src\drivers\h_bridge.c
h_bridge.c
0
0
4
21
1
0
0
0
0
.\src\drivers\incr_encoder.c
incr_encoder.c
0
0
4
22
1
0
0
0
0
.\src\drivers\uart.c
uart.c
0
0
4
23
1
0
0
0
0
.\src\drivers\hall.c
hall.c
0
0
4
24
1
0
0
0
0
.\src\drivers\strain_gauge.c
strain_gauge.c
0
0
4
25
1
0
0
0
0
.\src\drivers\tachometer.c
tachometer.c
0
0
SRC_lib
1
0
0
0
5
26
1
0
0
0
0
.\src\lib\basic_filter.c
basic_filter.c
0
0
5
27
1
0
0
0
0
.\src\lib\pid.c
pid.c
0
0
5
28
1
0
0
0
0
.\src\lib\utils.c
utils.c
0
0
+
+ 5
+ 29
+ 1
+ 0
+ 0
+ 0
+ 0
+ .\src\lib\circular_buffer.c
+ circular_buffer.c
+ 0
+ 0
+
diff --git a/Firmware/carteHRI.uvprojx b/Firmware/carteHRI.uvprojx
index 3b37fa6..a59f0aa 100644
--- a/Firmware/carteHRI.uvprojx
+++ b/Firmware/carteHRI.uvprojx
@@ -1,581 +1,586 @@
2.1
### uVision Project, (C) Keil Software
Target 1
0x4
ARM-ADS
STM32F407VG
STMicroelectronics
Keil.STM32F4xx_DFP.2.5.0
http://www.keil.com/pack
IROM(0x08000000,0x100000) IRAM(0x20000000,0x20000) IRAM2(0x10000000,0x10000) CPUTYPE("Cortex-M4") FPU2 CLOCK(168000000) ELITTLE
UL2CM3(-S0 -C0 -P0 -FD20000000 -FC1000 -FN1 -FF0STM32F4xx_1024 -FS08000000 -FL0100000 -FP0($$Device:STM32F407VG$Flash\STM32F4xx_1024.FLM))
6103
$$Device:STM32F407VG$Device\Include\stm32f4xx.h
$$Device:STM32F407VG$SVD\STM32F40x.svd
0
0
0
0
0
0
1
.\output\
motorControl
1
0
1
1
1
.\lst\
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
3
1
SARMCM3.DLL
-REMAP -MPU
DCM.DLL
-pCM4
SARMCM3.DLL
-REMAP -MPU
TCM.DLL
-pCM4
1
0
0
0
16
0
1
1
1
1
1
1
1
0
1
1
1
0
1
1
1
0
1
1
1
0
11
STLink\ST-LINKIII-KEIL_SWO.dll
1
0
0
1
1
4096
1
BIN\UL2CM3.DLL
"" ()
0
0
1
1
1
1
1
1
1
0
1
1
0
1
1
0
0
1
1
1
1
1
1
1
1
1
0
0
"Cortex-M4"
0
0
0
1
1
0
0
2
1
0
8
0
0
0
3
3
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
1
0
0
0x0
0x0
0
0x0
0x0
0
0x0
0x0
0
0x0
0x0
0
0x0
0x0
0
0x0
0x0
0
0x20000000
0x20000
1
0x8000000
0x100000
0
0x0
0x0
1
0x0
0x0
1
0x0
0x0
1
0x0
0x0
1
0x8000000
0x100000
1
0x0
0x0
0
0x0
0x0
0
0x0
0x0
0
0x0
0x0
0
0x20000000
0x20000
0
0x10000000
0x10000
1
4
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
USE_STDPERIPH_DRIVER STM32F4XX ARM_MATH_CM4
..\CodeUC;.\inc;.\src;C:\STM32F4-Discovery_FW_V1.1.0\Libraries\CMSIS\ST\STM32F4xx\Include;C:\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32F4xx_StdPeriph_Driver\inc;C:\STM32F4-Discovery_FW_V1.1.0\Utilities\STM32F4-Discovery;C:\STM32F4-Discovery_FW_V1.1.0\Libraries\CMSIS\Include
1
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0x08000000
0x20000000
STM32_files
system_stm32f4xx.c
1
.\src\system_stm32f4xx.c
startup_stm32f4xx.s
2
.\startup_stm32f4xx.s
SRC
main.c
1
.\src\main.c
communication.c
1
.\src\communication.c
controller.c
1
.\src\controller.c
STM32_libs
stm32f4xx_gpio.c
1
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32F4xx_StdPeriph_Driver\src\stm32f4xx_gpio.c
stm32f4xx_rcc.c
1
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32F4xx_StdPeriph_Driver\src\stm32f4xx_rcc.c
stm32f4xx_tim.c
1
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32F4xx_StdPeriph_Driver\src\stm32f4xx_tim.c
misc.c
1
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32F4xx_StdPeriph_Driver\src\misc.c
stm32f4xx_exti.c
1
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32F4xx_StdPeriph_Driver\src\stm32f4xx_exti.c
stm32f4xx_syscfg.c
1
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32F4xx_StdPeriph_Driver\src\stm32f4xx_syscfg.c
stm32f4xx_adc.c
1
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32F4xx_StdPeriph_Driver\src\stm32f4xx_adc.c
stm32f4xx_dac.c
1
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32F4xx_StdPeriph_Driver\src\stm32f4xx_dac.c
stm32f4xx_dma.c
1
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32F4xx_StdPeriph_Driver\src\stm32f4xx_dma.c
stm32f4xx_usart.c
1
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32F4xx_StdPeriph_Driver\src\stm32f4xx_usart.c
arm_cortexM4lf_math.lib
4
C:\STM32F4-Discovery_FW_V1.1.0\Libraries\CMSIS\Lib\ARM\arm_cortexM4lf_math.lib
SRC_drivers
adc.c
1
.\src\drivers\adc.c
callback_timers.c
1
.\src\drivers\callback_timers.c
dac.c
1
.\src\drivers\dac.c
h_bridge.c
1
.\src\drivers\h_bridge.c
incr_encoder.c
1
.\src\drivers\incr_encoder.c
uart.c
1
.\src\drivers\uart.c
hall.c
1
.\src\drivers\hall.c
strain_gauge.c
1
.\src\drivers\strain_gauge.c
tachometer.c
1
.\src\drivers\tachometer.c
SRC_lib
basic_filter.c
1
.\src\lib\basic_filter.c
pid.c
1
.\src\lib\pid.c
utils.c
1
.\src\lib\utils.c
+
+ circular_buffer.c
+ 1
+ .\src\lib\circular_buffer.c
+
diff --git a/Firmware/src/communication.c b/Firmware/src/communication.c
index 4ad4031..a3d2b8a 100644
--- a/Firmware/src/communication.c
+++ b/Firmware/src/communication.c
@@ -1,361 +1,378 @@
#include "communication.h"
#include "controller.h"
#include "drivers/callback_timers.h"
#include "drivers/adc.h"
#include "drivers/dac.h"
#include "drivers/incr_encoder.h"
#include "drivers/hall.h"
#include "drivers/strain_gauge.h"
#include "drivers/tachometer.h"
#include "drivers/uart.h"
#include "lib/basic_filter.h"
#include "lib/pid.h"
#include "lib/utils.h"
-#include
#include
extern uint32_t statusReg, ctrl_timestamp, ctrl_currentFilterType;
extern float32_t ctrl_motorPosCod, ctrl_motorPosCod_c;
extern float32_t ctrl_motorTorque_Nm_c, ctrl_motorPosCodFilt, ctrl_firstOrderFilterTau;
extern float32_t hall_angle, tac_speed, sg_force;
extern pid_Pid ctrl_positionPid;
extern bfilt_BasicFilter ctrl_encoderFilter;
extern float32_t ctrl_sineAmplitude, ctrl_sinePeriod;
uint32_t selectedVariablesToStream; // Bitfield that indicates for each variable if it should be streamed or not.
void* variablesArray[N_VARIABLES]; // Pointers to variables to stream.
uint8_t txBuffer[1024];
+#define COMM_BUFFER_SIZE 1024
#define DEBUG_MESSAGE_BUFFER_SIZE 1024
+
+uint8_t comm_packetTxBuffer[COMM_BUFFER_SIZE];
char comm_debugMessageBuffer[DEBUG_MESSAGE_BUFFER_SIZE];
+cb_CircularBuffer *comm_rxQueue;
uint8_t rxCurrentMessageType = PC_MESSAGE_DO_NOTHING; // Current message type for RX bytes.
uint32_t rxBytesCount; // Number of received bytes for the current message.
uint8_t firstHalfByte; // First half of the data byte to receive.
uint8_t rxDataBytesBuffer[32]; // Data bytes received (ready to use, bytes already merged).
void comm_SendPacket(uint8_t messageType, uint8_t *data, uint16_t dataLength);
void comm_HandleByte(uint8_t rxData);
void comm_Stream(void);
uint32_t comm_GetVar(uint8_t variableIndex);
/**
* @brief Init the communication manager.
*/
void comm_Init(void)
{
// Initialize the array with all the pointers on variables.
// Note that this array contains pointers only to uint32_t, even if the
// variables are actually float32_t. This does not matter, since we only use
// these pointers to perform byte-to-byte copies.
// Do not modify this by hand, copy-paste code generated by the excel sheet.
variablesArray[VAR_TIMESTAMP] = (uint32_t*) &ctrl_timestamp;
variablesArray[VAR_POS_REG_PID_P] = (uint32_t*) &ctrl_positionPid.kp;
variablesArray[VAR_POS_REG_PID_I] = (uint32_t*) &ctrl_positionPid.ki;
variablesArray[VAR_POS_REG_PID_D] = (uint32_t*) &ctrl_positionPid.kd;
variablesArray[VAR_POS_REG_PID_ARW] = (uint32_t*) &ctrl_positionPid.arw;
variablesArray[VAR_POS_REG_PID_INTEGRATOR] = (uint32_t*) &ctrl_positionPid.integrator;
variablesArray[VAR_POS_REG_PID_OUTPUT] = (uint32_t*) &ctrl_motorTorque_Nm_c;
variablesArray[VAR_POS_REG_SAMPLING_PERIOD] = NULL;
variablesArray[VAR_WALL_POSITION] = (uint32_t*) &ctrl_motorPosCod_c;
variablesArray[VAR_MEASURED_ANGLE_RAW] = NULL;
variablesArray[VAR_MEASURED_ANGLE_FILTERED] = (uint32_t*) &ctrl_motorPosCodFilt;
variablesArray[VAR_COMM_TX_PERIOD] = NULL;
variablesArray[VAR_ACTIVE_FILTER] = (uint32_t*) &ctrl_currentFilterType;
variablesArray[VAR_1ST_FILT_TAU] = (uint32_t*) &ctrl_encoderFilter.tau;
variablesArray[VAR_DAC1_VOLTAGE] = NULL;
variablesArray[VAR_DAC2_VOLTAGE] = NULL;
variablesArray[VAR_ADC1_VOLTAGE] = NULL;
variablesArray[VAR_ADC2_VOLTAGE] = NULL;
variablesArray[VAR_HALL_ANGLE] = NULL;
variablesArray[VAR_TACHO_SPEED] = NULL;
variablesArray[VAR_STRAIN_GAUGE_FORCE] = NULL;
variablesArray[VAR_USER_VAR_1] = NULL;
variablesArray[VAR_USER_VAR_2] = NULL;
variablesArray[VAR_USER_VAR_3] = NULL;
variablesArray[VAR_USER_VAR_4] = NULL;
variablesArray[VAR_USER_VAR_5] = NULL;
// Setup the UART peripheral, and specify the function that will be called
// each time a byte is received.
- uart_Init(comm_HandleByte);
+ uart_Init();
+ comm_rxQueue = uart_GetRxQueue();
+ rxCurrentMessageType = PC_MESSAGE_DO_NOTHING;
// Make the streaming function periodically called by the timer 7.
cbt_SetCommLoopTimer(comm_Stream, TE_DATA_LOOP_DEFAULT_VAL);
}
+void comm_Step(void)
+{
+ // Send the bytes in the TX queue, even if it is not full, to avoid latency.
+ uart_FlushTx();
+
+ // Interpret the bytes in the RX queue.
+ uart_Step();
+
+ while(!cb_IsEmpty(comm_rxQueue))
+ comm_HandleByte(cb_Pull(comm_rxQueue));
+}
+
/**
* @brief UART data streaming "loop" function.
*/
void comm_Stream()
{
// If the data streaming is enabled, send a stream packet to the PC.
if(statusReg & DATA_UPSTREAM_ENB)
{
uint32_t i;
int nDataBytesToSend = 0;
for(i=0; i> 4); // Most significant bits.
- uart_SendByte((data[i]&0x0f)); // Least significant bits.
+ *p = ((data[i]&0xf0) >> 4); // Most significant bits.
+ p++;
+ *p = ((data[i]&0x0f)); // Least significant bits.
+ p++;
}
+
+ uart_SendBytesAsync(comm_packetTxBuffer, dataLength*2+1);
}
/**
* @brief Process the received byte to interpret the messages.
* @param rxData: the byte to be processed and interpreted.
*/
void comm_HandleByte(uint8_t rxData)
{
if(rxData & (1<<7)) // The start byte has the most significant bit high.
{
rxCurrentMessageType = (rxData & ~(1<<7)); // Remove the start bit.
rxBytesCount = 0;
}
else
rxBytesCount++;
if(rxBytesCount % 2 == 1) // First half of the data byte has been received.
firstHalfByte = rxData; // Store it until the second half arrives.
else // Second half of the data byte has been received (or no data bytes yet).
{
int dataBytesReady = rxBytesCount/2;
rxDataBytesBuffer[dataBytesReady-1] = (firstHalfByte<<4) + (rxData & 0xf);
switch(rxCurrentMessageType)
{
case PC_MESSAGE_DO_NOTHING:
if(dataBytesReady == 0)
; // Do nothing.
break;
case PC_MESSAGE_SEND_STATUS:
if(dataBytesReady == 0)
comm_SendPacket(STM_MESSAGE_STATUS, (uint8_t*)(&statusReg), 4);
break;
case PC_MESSAGE_START_STREAMING:
if(dataBytesReady == 0)
{
statusReg |= DATA_UPSTREAM_ENB;
TIM_SetCounter(TIM7, 0);
TIM_Cmd(TIM7, ENABLE);
}
break;
case PC_MESSAGE_STOP_STREAMING:
if(dataBytesReady == 0)
{
TIM_Cmd(TIM7, DISABLE);
statusReg &= ~DATA_UPSTREAM_ENB;
}
break;
case PC_MESSAGE_GET_VAR:
if(dataBytesReady == 1)
{
uint32_t variableValue;
// Extract the index, that indicates which variable will be sent.
uint8_t variableIndex = rxDataBytesBuffer[0];
// If the variable index is out of range, ignore the request.
if(variableIndex >= N_VARIABLES)
return;
// Prepare the message to be sent to the PC.
// First byte: variable index.
txBuffer[0] = variableIndex;
// Four following bytes: actual value of the variable.
variableValue = comm_GetVar(variableIndex);
memcpy(&txBuffer[1], &variableValue, 4);
// Send the message to the PC.
comm_SendPacket(STM_MESSAGE_VAR, txBuffer, 5);
}
break;
case PC_MESSAGE_SET_VAR:
if(dataBytesReady == 5)
{
// Extract the index (that indicates which variable will change),
// and the new value of the variable.
uint32_t newValue;
uint8_t variableIndex = rxDataBytesBuffer[0];
memcpy(&newValue, &rxDataBytesBuffer[1], 4);
// Set the selected variable with the new value.
comm_SetVar(variableIndex, newValue);
}
break;
case PC_MESSAGE_SET_STREAMED_VAR:
if(dataBytesReady == 4)
{
uint8_t *newSelectedVars = &rxDataBytesBuffer[0];
memcpy(&selectedVariablesToStream, newSelectedVars, 4);
}
break;
default: // No data bytes for the other message types.
break;
}
}
}
-void comm_SendDebugMessage(char format[], ...)
+/**
+ * @brief Sends a debug message to the computer.
+ * @param format format string.
+ * @param ... variables to be printed in the format string.
+ */
+void comm_SendDebugMessage(const char* format, ...)
{
+ uint16_t length;
va_list args;
- va_start(args, format);
- snprintf(comm_debugMessageBuffer, DEBUG_MESSAGE_BUFFER_SIZE,
- format, args);
- va_end(args);
+
+ va_start(args, format);
+
+ length = vsnprintf(comm_debugMessageBuffer, DEBUG_MESSAGE_BUFFER_SIZE,
+ format, args);
comm_SendPacket(STM_MESSAGE_DEBUG_TEXT, (uint8_t*)comm_debugMessageBuffer,
- strlen(comm_debugMessageBuffer));
-}
+ length+1);
-#define comm_SendDebugMessageDecimatedII(decimation, COUNTER, message, ...) \
- static int comm_decim##COUNTER = 0; \
- if(comm_decim##COUNTER++ % decimation == 0) \
- comm_SendDebugMessage(message, __VA_ARGS__);
-
-#define comm_SendDebugMessageDecimatedI(decimation, format, ...) \
- do { \
- comm_SendDebugMessageDecimatedII(decimation, __COUNTER__, format, __VA_ARGS__) \
- } while(0)
-
-void comm_SendDebugMessageDecimated(int decimation, char format[], ...)
-{
- va_list args;
- va_start(args, format);
- comm_SendDebugMessageDecimatedI(decimation, format, args);
- va_end(args);
+ va_end(args);
}
+
diff --git a/Firmware/src/communication.h b/Firmware/src/communication.h
index fa8228e..bf1c710 100644
--- a/Firmware/src/communication.h
+++ b/Firmware/src/communication.h
@@ -1,79 +1,57 @@
#ifndef __COMMUNICATION_H
#define __COMMUNICATION_H
#include "main.h"
+#include "definitions.h"
-// Message IDs sent by host (PC) to the device (STM).
-#define PC_MESSAGE_DO_NOTHING 0 // Do nothing.
-#define PC_MESSAGE_TOGGLE_LED 1 // Toggle the LED (debug).
-#define PC_MESSAGE_SEND_STATUS 2 // Request the device to send the main status register.
-#define PC_MESSAGE_START_STREAMING 3 // Request the device to start streaming continuously.
-#define PC_MESSAGE_STOP_STREAMING 4 // Request the device to stop streaming continuously.
-#define PC_MESSAGE_GET_VAR 5 // Request the device to send the selected value.
-#define PC_MESSAGE_SET_VAR 6 // Set the selected variable.
-#define PC_MESSAGE_SET_STREAMED_VAR 7 // Set the variables to be streamed.
-
-// Message IDs sent by device (STM) to the device (PC).
-#define STM_MESSAGE_STATUS 0 // Main status register.
-#define STM_MESSAGE_VAR 1 // Variable state.
-#define STM_MESSAGE_STREAMING_PACKET 2 // Streaming packet.
-#define STM_MESSAGE_DEBUG_TEXT 3 // Debug text message.
-
-// Variables IDs.
-#define VAR_TIMESTAMP 0 // Timestamp. [us]
-#define VAR_POS_REG_PID_P 1 // Position regulator - proportionnal coefficient. [1]
-#define VAR_POS_REG_PID_I 2 // Position regulator - integral coefficient. [1]
-#define VAR_POS_REG_PID_D 3 // Position regulator - derivative coefficient. [1]
-#define VAR_POS_REG_PID_ARW 4 // Position regulator - ARW (integrator max value). [1]
-#define VAR_POS_REG_PID_INTEGRATOR 5 // Position regulator - integrator state. [1]
-#define VAR_POS_REG_PID_OUTPUT 6 // Position regulator - output. [mN.m]
-#define VAR_POS_REG_SAMPLING_PERIOD 7 // Position regulator - sampling period [us]
-#define VAR_WALL_POSITION 8 // Position regulator - target (wall position). [pulses]
-#define VAR_MEASURED_ANGLE_RAW 9 // Measured output angle, unfiltered. [deg]
-#define VAR_MEASURED_ANGLE_FILTERED 10 // Measured output angle, filtered. [deg]
-#define VAR_COMM_TX_PERIOD 11 // Communication loop - sending period. [us]
-#define VAR_ACTIVE_FILTER 12 // Active filter type (0: none, 1: first-order, 2: running mean). [None]
-#define VAR_1ST_FILT_TAU 13 // First order filter - time constant. [1]
-#define VAR_DAC1_VOLTAGE 14 // DAC 1 channel voltage. [V]
-#define VAR_DAC2_VOLTAGE 15 // DAC 2 channel voltage. [V]
-#define VAR_ADC1_VOLTAGE 16 // ACDC 1 channel voltage. [V]
-#define VAR_ADC2_VOLTAGE 17 // ACDC 2 channel voltage. [V]
-#define VAR_HALL_ANGLE 18 // Angle measured by the Hall sensor. [deg]
-#define VAR_TACHO_SPEED 19 // Angular speed measured by the tachometer. [deg/s]
-#define VAR_STRAIN_GAUGE_FORCE 20 // Force measured by the strain gauge. [?]
-#define VAR_USER_VAR_1 21 // User Variable 1 []
-#define VAR_USER_VAR_2 22 // User Variable 2 []
-#define VAR_USER_VAR_3 23 // User Variable 3 []
-#define VAR_USER_VAR_4 24 // User Variable 4 []
-#define VAR_USER_VAR_5 25 // User Variable 5 []
-
-#define N_VARIABLES 26 // Number of variables, used for enumeration of all variables.
+#include
/** @defgroup Communication Main / Communication
* @brief Control the communication with the computer.
*
* This module controls all the communication logic between the board and the
* computer. It uses a specific communication protocol between the
* computer and the board, with a system of messages. Thanks to this, the
* the MATLAB application is able to get the value of selected variables on the
* STM, and is even capable of modifiying them remotely.
*
* Make sure that the files communication.h/.c are up-to-date with the Excel
* spreadsheet "Protocol description.xlsx".
*
* Call comm_Init() to setup this module. Its interrupt function will be called
* automatically when a message arrives, or periodically when the data
* streaming is enabled.
*
* @addtogroup Communication
* @{
*/
void comm_Init(void);
-void comm_SendDebugMessage(char format[], ...);
-void comm_SendDebugMessageDecimated(int decimation, char format[], ...);
+void comm_Step(void);
+void comm_SendDebugMessage(const char *format, ...);
+
+/**
+ * @brief Sends a debug message to the computer, with decimation.
+ * This macro is useful to print human-readable text, in a fast loop, to avoid
+ * overloading the communication bus, or the computer.
+ * @param decimation this macro will actually print once out of decimation, and
+ * do nothing otherwise.
+ * @param format format string. See the printf() documentation for format
+ * specification.
+ * @param ... variables to be printed in the format string.
+ */
+#define comm_SendDebugMessageDecimated(decimation, format, ...) \
+do \
+{ \
+ static int comm_decim##__COUNTER__ = 0; \
+ if(comm_decim##__COUNTER__++ % decimation == 0) \
+ { \
+ comm_SendDebugMessage(format, ##__VA_ARGS__); \
+ } \
+} while(0)
+
/**
* @}
*/
#endif
diff --git a/Firmware/src/communication.h b/Firmware/src/definitions.h
similarity index 72%
copy from Firmware/src/communication.h
copy to Firmware/src/definitions.h
index fa8228e..9f263b2 100644
--- a/Firmware/src/communication.h
+++ b/Firmware/src/definitions.h
@@ -1,79 +1,50 @@
-#ifndef __COMMUNICATION_H
-#define __COMMUNICATION_H
-
-#include "main.h"
+#ifndef DEF_DEFINITIONS_H
+#define DEF_DEFINITIONS_H
// Message IDs sent by host (PC) to the device (STM).
#define PC_MESSAGE_DO_NOTHING 0 // Do nothing.
#define PC_MESSAGE_TOGGLE_LED 1 // Toggle the LED (debug).
#define PC_MESSAGE_SEND_STATUS 2 // Request the device to send the main status register.
#define PC_MESSAGE_START_STREAMING 3 // Request the device to start streaming continuously.
#define PC_MESSAGE_STOP_STREAMING 4 // Request the device to stop streaming continuously.
#define PC_MESSAGE_GET_VAR 5 // Request the device to send the selected value.
#define PC_MESSAGE_SET_VAR 6 // Set the selected variable.
#define PC_MESSAGE_SET_STREAMED_VAR 7 // Set the variables to be streamed.
// Message IDs sent by device (STM) to the device (PC).
#define STM_MESSAGE_STATUS 0 // Main status register.
#define STM_MESSAGE_VAR 1 // Variable state.
#define STM_MESSAGE_STREAMING_PACKET 2 // Streaming packet.
#define STM_MESSAGE_DEBUG_TEXT 3 // Debug text message.
// Variables IDs.
#define VAR_TIMESTAMP 0 // Timestamp. [us]
#define VAR_POS_REG_PID_P 1 // Position regulator - proportionnal coefficient. [1]
#define VAR_POS_REG_PID_I 2 // Position regulator - integral coefficient. [1]
#define VAR_POS_REG_PID_D 3 // Position regulator - derivative coefficient. [1]
#define VAR_POS_REG_PID_ARW 4 // Position regulator - ARW (integrator max value). [1]
#define VAR_POS_REG_PID_INTEGRATOR 5 // Position regulator - integrator state. [1]
#define VAR_POS_REG_PID_OUTPUT 6 // Position regulator - output. [mN.m]
#define VAR_POS_REG_SAMPLING_PERIOD 7 // Position regulator - sampling period [us]
#define VAR_WALL_POSITION 8 // Position regulator - target (wall position). [pulses]
#define VAR_MEASURED_ANGLE_RAW 9 // Measured output angle, unfiltered. [deg]
#define VAR_MEASURED_ANGLE_FILTERED 10 // Measured output angle, filtered. [deg]
#define VAR_COMM_TX_PERIOD 11 // Communication loop - sending period. [us]
#define VAR_ACTIVE_FILTER 12 // Active filter type (0: none, 1: first-order, 2: running mean). [None]
#define VAR_1ST_FILT_TAU 13 // First order filter - time constant. [1]
#define VAR_DAC1_VOLTAGE 14 // DAC 1 channel voltage. [V]
#define VAR_DAC2_VOLTAGE 15 // DAC 2 channel voltage. [V]
#define VAR_ADC1_VOLTAGE 16 // ACDC 1 channel voltage. [V]
#define VAR_ADC2_VOLTAGE 17 // ACDC 2 channel voltage. [V]
#define VAR_HALL_ANGLE 18 // Angle measured by the Hall sensor. [deg]
#define VAR_TACHO_SPEED 19 // Angular speed measured by the tachometer. [deg/s]
#define VAR_STRAIN_GAUGE_FORCE 20 // Force measured by the strain gauge. [?]
#define VAR_USER_VAR_1 21 // User Variable 1 []
#define VAR_USER_VAR_2 22 // User Variable 2 []
#define VAR_USER_VAR_3 23 // User Variable 3 []
#define VAR_USER_VAR_4 24 // User Variable 4 []
#define VAR_USER_VAR_5 25 // User Variable 5 []
#define N_VARIABLES 26 // Number of variables, used for enumeration of all variables.
-/** @defgroup Communication Main / Communication
- * @brief Control the communication with the computer.
- *
- * This module controls all the communication logic between the board and the
- * computer. It uses a specific communication protocol between the
- * computer and the board, with a system of messages. Thanks to this, the
- * the MATLAB application is able to get the value of selected variables on the
- * STM, and is even capable of modifiying them remotely.
- *
- * Make sure that the files communication.h/.c are up-to-date with the Excel
- * spreadsheet "Protocol description.xlsx".
- *
- * Call comm_Init() to setup this module. Its interrupt function will be called
- * automatically when a message arrives, or periodically when the data
- * streaming is enabled.
- *
- * @addtogroup Communication
- * @{
- */
-
-void comm_Init(void);
-void comm_SendDebugMessage(char format[], ...);
-void comm_SendDebugMessageDecimated(int decimation, char format[], ...);
-/**
- * @}
- */
-
#endif
diff --git a/Firmware/src/drivers/callback_timers.c b/Firmware/src/drivers/callback_timers.c
index d1e98ea..1e4d267 100644
--- a/Firmware/src/drivers/callback_timers.c
+++ b/Firmware/src/drivers/callback_timers.c
@@ -1,230 +1,227 @@
#include "callback_timers.h"
#include "../controller.h"
#include "../lib/utils.h"
cbt_PeriodicTaskFunc cbt_tim1Task, cbt_tim6Task, cbt_tim7Task;
volatile float32_t cbt_ucLoad; // Processor load (%).
void tim1InitFunc(void);
void tim67InitFunc(void);
/**
* @brief Initialize the timers to call an interrupt routine periodically.
*/
void cbt_Init(void)
-{
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_GPIOE, ENABLE);
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); // ???
-
+{
// Initialize the timers.
tim1InitFunc();
tim67InitFunc();
// Initialize the function pointers to NULL, in order to be able to test
// if they are already affected or not.
cbt_tim1Task = NULL;
cbt_tim6Task = NULL;
cbt_tim7Task = NULL;
}
/**
* @brief Set the function to call periodically by the timer 1.
* @param f: the function to call periodically.
* @param period: the period between each call of f [us].
*/
void cbt_SetCurrentLoopTimer(cbt_PeriodicTaskFunc f, uint32_t period)
{
cbt_tim1Task = f;
utils_SaturateU(&period, TE_LOOP_MIN_VALUE, TE_LOOP_MAX_VALUE);
TIM1->ARR = (uint16_t) period;
}
/**
* @brief Set the function to call periodically by the timer 6.
* @param f: the function to call periodically.
* @param period: the period between each call of f [us].
*/
void cbt_SetPositionLoopTimer(cbt_PeriodicTaskFunc f, uint32_t period)
{
cbt_tim6Task = f;
utils_SaturateU(&period, TE_LOOP_MIN_VALUE, TE_LOOP_MAX_VALUE);
TIM6->ARR = (uint16_t) period;
}
/**
* @brief Set the function to call periodically by the timer 7.
* @param f: the function to call periodically.
* @param period: the period between each call of f [us].
*/
void cbt_SetCommLoopTimer(cbt_PeriodicTaskFunc f, uint32_t period)
{
cbt_tim7Task = f;
utils_SaturateU(&period, TE_LOOP_MIN_VALUE, TE_LOOP_MAX_VALUE);
TIM7->ARR = (uint16_t) period;
}
/**
* @brief Initialize TIM1 used for timing the current loop (resolution 1us).
*/
void tim1InitFunc(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
//TIM_OCInitTypeDef TIM_OCInitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
NVIC_InitStruct.NVIC_IRQChannel = TIM1_UP_TIM10_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = CURRENT_LOOP_IRQ_PRIORITY;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
TIM_TimeBaseStruct.TIM_Period = (uint16_t)(TE_CURRENT_LOOP_DEFAULT_VAL-1);
TIM_TimeBaseStruct.TIM_Prescaler = TIM1_PRESCALER;
TIM_TimeBaseStruct.TIM_ClockDivision = 0; // TIM_CKD_DIV2;
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStruct);
TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM1, ENABLE);
}
/**
* @brief Initialize TIM6, for timing the main control loop (resolution 1us)
* Initialize TIM7, for timing the data transmission loop (resolution 1us)
*/
void tim67InitFunc(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6|RCC_APB1Periph_TIM7, ENABLE);
NVIC_InitStruct.NVIC_IRQChannel = TIM6_DAC_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = CONTROL_LOOP_IRQ_PRIORITY;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel = TIM7_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = DATA_LOOP_IRQ_PRIORITY;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStruct);
TIM_TimeBaseStructInit(&TIM_TimeBaseStruct);
TIM_TimeBaseStruct.TIM_Prescaler = TIM6_PRESCALER;
TIM_TimeBaseStruct.TIM_Period = (uint16_t)(TE_CONTROL_LOOP_DEFAULT_VAL-1);
TIM_TimeBaseStruct.TIM_ClockDivision = 0;
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStruct);
TIM_TimeBaseStructInit(&TIM_TimeBaseStruct);
TIM_TimeBaseStruct.TIM_Prescaler = TIM7_PRESCALER;
TIM_TimeBaseStruct.TIM_Period = (uint16_t)(TE_DATA_LOOP_DEFAULT_VAL-1);
TIM_TimeBaseStruct.TIM_ClockDivision = 0;
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStruct);
TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
TIM_ITConfig(TIM7, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM6, ENABLE);
TIM_Cmd(TIM7, DISABLE);
}
/**
* @brief Interrupt from current control loop timer (TIM1)
*/
void TIM1_UP_TIM10_IRQHandler(void)
{
if(TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET)
{
if(cbt_tim1Task != NULL)
cbt_tim1Task();
TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
}
}
/**
* @brief Interrupt from main control loop timer (TIM6)
*/
void TIM6_DAC_IRQHandler(void)
{
if(TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)
{
if(cbt_tim6Task != NULL)
cbt_tim6Task();
// Percentage of time consumed by the control task 0..100%.
cbt_ucLoad = (((float32_t)(TIM6->CNT))*100)/((float32_t)(TIM6->ARR));
TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
}
}
/**
* @brief Interrupt from data transmission loop timer (TIM7) (data loop)
*/
void TIM7_IRQHandler(void)
{
if(TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET)
{
if(cbt_tim7Task != NULL)
cbt_tim7Task();
TIM_ClearITPendingBit(TIM7, TIM_IT_Update);
}
}
/**
* @brief Set the period of the position loop.
* @param period: the new period of the position loop [us].
*/
void cbt_SetPositionLoopPeriod(uint32_t period)
{
utils_SaturateU(&period, TE_LOOP_MIN_VALUE, TE_LOOP_MAX_VALUE);
TIM6->ARR = period;
}
/**
* @brief Set the period of the communication loop.
* @param period: the new period of the communication loop [us].
*/
void cbt_SetCommLoopPeriod(uint32_t period)
{
utils_SaturateU(&period, TE_LOOP_MIN_VALUE, TE_LOOP_MAX_VALUE);
TIM7->ARR = period;
}
/**
* @brief Get the period of the current loop.
* @return the period of the current loop [us].
*/
uint32_t cbt_GetCurrentLoopPeriod(void)
{
return TIM1->ARR;
}
/**
* @brief Get the period of the position loop.
* @return the period of the position loop [us].
*/
uint32_t cbt_GetPositionLoopPeriod(void)
{
return TIM6->ARR;
}
/**
* @brief Get the period of the communication loop.
* @return the period of the communication loop [us].
*/
uint32_t cbt_GetCommLoopPeriod(void)
{
return TIM7->ARR;
}
diff --git a/Firmware/src/drivers/uart.c b/Firmware/src/drivers/uart.c
index 1460998..8030485 100644
--- a/Firmware/src/drivers/uart.c
+++ b/Firmware/src/drivers/uart.c
@@ -1,95 +1,281 @@
#include "uart.h"
+#include "../lib/utils.h"
+#include "../communication.h" // TODO: REMOVE. DEBUG ONLY.
-uart_rxByteHandlerFunc uart_rxHandler;
+#define UART_RX_DMA DMA1_Stream5
+#define UART_RX_DMA_CHANNEL DMA_Channel_4
+#define UART_TX_DMA DMA1_Stream6
+#define UART_TX_DMA_CHANNEL DMA_Channel_4
+
+#define UART_TX_BUFFER_SIZE 512
+#define UART_RX_BUFFER_SIZE 512
+#define UART_USER_RX_QUEUE_SIZE 512
+
+uint8_t uart_txBuffer[2][UART_TX_BUFFER_SIZE];
+uint8_t uart_currentTxBufferToWriteTo;
+uint16_t uart_txBufferIndex;
+uint16_t uart_nBytesToTransferDma;
+
+uint8_t uart_rxBuffer[UART_RX_BUFFER_SIZE];
+uint8_t const * uart_rxBuffTail;
+
+uint8_t uart_userRxQueue[UART_USER_RX_QUEUE_SIZE];
+cb_CircularBuffer uart_rxQueue;
+
+#define UART_DMA_TX_IS_BUSY (DMA_GetCmdStatus(UART_TX_DMA) == ENABLE && DMA_GetCurrDataCounter(UART_TX_DMA) > 0)
/**
- * @brief Initialize the UART module.
- * @param f: a pointer to the function to be called each time a byte arrives.
+ * @brief Initializes the UART module.
*/
-void uart_Init(uart_rxByteHandlerFunc f)
+void uart_Init(void)
{
- GPIO_InitTypeDef GPIO_InitStruct;
+ GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
- NVIC_InitTypeDef NVIC_InitStruct;
-
- // Periph clock enable
+ DMA_InitTypeDef DMA_InitStruct;
+
+ // Enable UART and DMA peripherals clocks.
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
- // GPIO (PC10 & PC11)
+ // Setup GPIOs as UART pins.
GPIO_InitStruct.GPIO_Pin = USART_TX_Pin;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(USART_TX_Port, &GPIO_InitStruct);
GPIO_PinAFConfig(USART_TX_Port, USART_TX_PinSource, GPIO_AF_USART2);
GPIO_InitStruct.GPIO_Pin = USART_RX_Pin;
GPIO_Init(USART_RX_Port, &GPIO_InitStruct);
GPIO_PinAFConfig(USART_RX_Port, USART_RX_PinSource, GPIO_AF_USART2);
- // UART config
+ // Setup the UART peripheral.
USART_InitStruct.USART_BaudRate = USART_BAUDRATE;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
- USART_InitStruct.USART_StopBits = USART_StopBits_1; // 1 stop bit (standard)
+ USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
- USART_InitStruct.USART_Mode = USART_Mode_Tx|USART_Mode_Rx; //Two way datas
- USART_Init(USART2, &USART_InitStruct);
+ USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
+ USART_Init(USART_PC_COMM, &USART_InitStruct);
+
+ USART_Cmd(USART_PC_COMM, ENABLE);
+
+ // Setup the DMA for RX.
+ DMA_DeInit(UART_RX_DMA);
- // USART Rx interrupt
- USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
- NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQn;
- NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = UART_RX_IRQ_PRIORIY;
- NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
- NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStruct);
+ DMA_InitStruct.DMA_Channel = UART_RX_DMA_CHANNEL;
+ DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR;
+ DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)&uart_rxBuffer[0];
+ DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory;
+ DMA_InitStruct.DMA_BufferSize = UART_RX_BUFFER_SIZE;
+ DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
+ DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
+ DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
+ DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
+ DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
+ DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;
+ DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
+ DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
+ DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
+
+ DMA_Init(UART_RX_DMA, &DMA_InitStruct);
- USART_Cmd(USART2, ENABLE);
+ USART_DMACmd(USART_PC_COMM, USART_DMAReq_Rx | USART_DMAReq_Tx, ENABLE);
+ DMA_ITConfig(UART_RX_DMA, DMA_IT_TC, ENABLE);
+ DMA_Cmd(UART_RX_DMA, ENABLE);
+
+ uart_rxBuffTail = &uart_rxBuffer[0];
+
+ // Setup the DMA for TX.
+ DMA_DeInit(UART_TX_DMA);
+
+ DMA_InitStruct.DMA_Channel = UART_TX_DMA_CHANNEL;
+ DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR;
+ DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)&uart_txBuffer[0][0];
+ DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;
+ DMA_InitStruct.DMA_BufferSize = UART_TX_BUFFER_SIZE;
+ DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
+ DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
+ DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
+ DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
+ DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
+ DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;
+ DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
+ DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
+ DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
+
+ DMA_Init(UART_TX_DMA, &DMA_InitStruct);
- // Function called when a byte arrives, to process it.
- uart_rxHandler = f;
+ USART_DMACmd(USART_PC_COMM, USART_DMAReq_Rx | USART_DMAReq_Tx, ENABLE);
+ DMA_ITConfig(UART_TX_DMA, DMA_IT_TC, ENABLE);
+ //DMA_Cmd(UART_TX_DMA, ENABLE);
+
+ // Initialize the RX circular buffer.
+ cb_Init(&uart_rxQueue, uart_userRxQueue, UART_USER_RX_QUEUE_SIZE);
+
+ // Initialize the variables for the UART TX.
+ uart_currentTxBufferToWriteTo = 0;
+ uart_txBufferIndex = 0;
+ uart_nBytesToTransferDma = 0;
}
/**
- * @brief Get the received byte, and send it to the specified RX handler.
- * @note Called by the received byte interrupt.
- */
-void USART2_IRQHandler(void)
+ * @brief Copies the received bytes into the user-accessible queue.
+ * Reads all the available bytes in the DMA RX buffer, and copies them to the
+ * user-accessible queue.
+ * @remark This function must called often, otherwise the DMA RX buffer may be
+ * full.
+ */
+void uart_Step(void)
{
- if(USART_GetITStatus(USART2, USART_IT_RXNE))
+ // Get the location of the location currently pointed by the DMA.
+ uint8_t const * head = uart_rxBuffer + UART_RX_BUFFER_SIZE
+ - DMA_GetCurrDataCounter(UART_RX_DMA);
+
+ // Even if the STM32F4 reference manual (RM0090) states that the NDTR
+ // register is decremented after the transfer, this is not the case.
+ // So we wait a few cycles to be sure that the DMA actually performed the
+ // transfer.
+ utils_DelayUs(1);
+
+ // RX: add the received bytes into the user queue.
+ while(uart_rxBuffTail != head)
{
- uint8_t rxData = USART2->DR; // Read the DataRegister (also clears the RX interrupt pending bit).
-
- // Call the external RX byte handler.
- uart_rxHandler(rxData);
+ uint8_t b = *uart_rxBuffTail;
+ cb_Push(&uart_rxQueue, b);
+
+ uart_rxBuffTail++;
+
+ if(uart_rxBuffTail >= uart_rxBuffer + UART_RX_BUFFER_SIZE)
+ uart_rxBuffTail -= UART_RX_BUFFER_SIZE;
}
}
+/**
+ * @brief Gets the user-accessible queue of the received bytes.
+ * @return the address of the queue.
+ */
+cb_CircularBuffer* uart_GetRxQueue(void)
+{
+ return &uart_rxQueue;
+}
/**
- * @brief Sent a byte through UART.
- * @param data: byte to send through UART.
- * @note This function blocks until the byte is sent.
- */
-void uart_SendByte(uint8_t data)
+ * @brief Starts the DMA transfer to send bytes to UART peripheral.
+ */
+void uart_StartDma(void)
{
- while( !(USART_PC_COMM->SR & 0x00000040) ) // Wait until data register is empty.
- ;
- USART_SendData(USART_PC_COMM, data);
+ DMA_InitTypeDef DMA_InitStruct;
+
+ //
+ uart_nBytesToTransferDma = uart_txBufferIndex;
+ uart_currentTxBufferToWriteTo = !uart_currentTxBufferToWriteTo;
+ uart_txBufferIndex = 0;
+
+ // Start the DMA transfer.
+ DMA_DeInit(UART_TX_DMA);
+
+ DMA_InitStruct.DMA_Channel = UART_TX_DMA_CHANNEL;
+ DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR;
+ DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)&uart_txBuffer[!uart_currentTxBufferToWriteTo][0];
+ DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;
+ DMA_InitStruct.DMA_BufferSize = uart_nBytesToTransferDma;
+ DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
+ DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
+ DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
+ DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
+ DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
+ DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;
+ DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
+ DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
+ DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
+
+ DMA_Init(UART_TX_DMA, &DMA_InitStruct);
+
+ DMA_Cmd(UART_TX_DMA, ENABLE);
}
/**
- * @brief Sent an array of bytes through UART.
- * @note This function blocks until all the bytes are sent.
- * @param data: bytes array to send through UART.
- * @param length: number of bytes in the array.
- */
-void uart_SendBytes(uint8_t *data, int length)
+ * @brief Asynchronously sends the given byte through the UART bus.
+ * @param data the data byte to send.
+ */
+void uart_SendByteAsync(uint8_t data)
+{
+ // Check that it is possible to write in the current buffer.
+ if(uart_txBufferIndex >= UART_TX_BUFFER_SIZE)
+ {
+ // If the DMA is idle, switch to the other buffer.
+ if(UART_DMA_TX_IS_BUSY)
+ {
+ utils_TrapCpu(); // Error, can't write anywhere!
+ return;
+ }
+ else
+ uart_StartDma();
+ }
+
+ // Write the byte in the buffer.
+ uart_txBuffer[uart_currentTxBufferToWriteTo][uart_txBufferIndex] = data;
+ uart_txBufferIndex++;
+
+ // If the buffer is full, start the DMA transfer.
+ if(uart_txBufferIndex == UART_TX_BUFFER_SIZE)
+ uart_StartDma();
+}
+
+/**
+ * @brief Asynchronously sends the given bytes through the UART bus.
+ * @param data pointer to the data bytes array to send.
+ * @param length number of bytes to send (array size).
+ * @remark The bytes may not be send immediately, they are stored temporarily in
+ * an intermediate buffer that the DMA will copy to UART peripheral, when it is
+ * full. Call uart_FlushTx() to start the DMA transfer immediately.
+ */
+void uart_SendBytesAsync(uint8_t *data, int length)
{
- int i;
+ while(length > 0)
+ {
+ uint16_t nBytesToWriteInBuf;
- for(i=0; i= UART_TX_BUFFER_SIZE)
+ {
+ // If the DMA is idle, switch to the other buffer.
+ if(UART_DMA_TX_IS_BUSY)
+ {
+ utils_TrapCpu(); // Error, can't write anywhere!
+ return;
+ }
+ else
+ uart_StartDma();
+ }
+
+ // Write as many bytes as possible in the current buffer.
+ nBytesToWriteInBuf = UART_TX_BUFFER_SIZE - uart_txBufferIndex;
+
+ if(nBytesToWriteInBuf > length)
+ nBytesToWriteInBuf = length;
+
+ memcpy(&uart_txBuffer[uart_currentTxBufferToWriteTo][uart_txBufferIndex],
+ data, nBytesToWriteInBuf);
+ uart_txBufferIndex += nBytesToWriteInBuf;
+
+ data += nBytesToWriteInBuf;
+ length -= nBytesToWriteInBuf;
+
+ // If the buffer is full, start the DMA transfer.
+ if(uart_txBufferIndex == UART_TX_BUFFER_SIZE)
+ uart_StartDma();
+ }
+}
+
+/**
+ * @brief Start the DMA to send the bytes waiting in the intermediate buffer.
+ */
+void uart_FlushTx(void)
+{
+ if(uart_txBufferIndex > 0 && !UART_DMA_TX_IS_BUSY)
+ uart_StartDma();
}
diff --git a/Firmware/src/drivers/uart.h b/Firmware/src/drivers/uart.h
index 9999532..8a83d89 100644
--- a/Firmware/src/drivers/uart.h
+++ b/Firmware/src/drivers/uart.h
@@ -1,48 +1,52 @@
#ifndef __UART_H
#define __UART_H
#include "../main.h"
+#include "../lib/circular_buffer.h"
#define USART_RX_Pin GPIO_Pin_5
#define USART_RX_PinSource GPIO_PinSource5
#define USART_RX_Port GPIOD
#define USART_TX_Pin GPIO_Pin_6
#define USART_TX_PinSource GPIO_PinSource6
#define USART_TX_Port GPIOD
#define USART_PC_COMM USART2 // UART peripheral used for the comm with the PC.
#define USART_BAUDRATE 1843200 //921600 // USART baudrate [b/s].
/** @defgroup UART Driver / UART
* @brief Driver for the UART serial communication peripheral.
*
* This driver controls the UART peripheral of the STM32, connected to the
* USB-to-serial chip.
*
* Call uart_Init() first in the initialization code, specifiying the function
* to call when a byte arrives (sent from the computer). To send data, call
* uart_SendByte() or uart_SendBytes().
*
* Note that this module should not be used directly. It is a better option to
* use it through the Communication module, to benefit from the already
* implemented communication protocol between the board and MATLAB.
*
* @addtogroup UART
* @{
*/
/**
* Typedef for a pointer to a function to call automatically when a byte
* arrives from the computer.
*/
typedef void (*uart_rxByteHandlerFunc)(uint8_t rxByte);
-void uart_Init(uart_rxByteHandlerFunc f);
-void uart_SendByte(uint8_t data);
-void uart_SendBytes(uint8_t *data, int length);
+void uart_Init(void);
+void uart_Step(void);
+cb_CircularBuffer* uart_GetRxQueue(void);
+void uart_SendByteAsync(uint8_t data);
+void uart_SendBytesAsync(uint8_t *data, int length);
+void uart_FlushTx(void);
/**
* @}
*/
#endif
diff --git a/Firmware/src/lib/circular_buffer.c b/Firmware/src/lib/circular_buffer.c
new file mode 100644
index 0000000..3f847b6
--- /dev/null
+++ b/Firmware/src/lib/circular_buffer.c
@@ -0,0 +1,109 @@
+#include "circular_buffer.h"
+#include "utils.h"
+
+/**
+ * @brief Initializes a cb_CircularBuffer structure.
+ * Initializes a cb_CircularBuffer structure with the given buffer. The buffer
+ * has to be provided by the user, to avoid dynamic memory allocation.
+ * @param cb the cb_CircularBuffer structure to initialize.
+ * @param buffer pointer to an existing array.
+ * @param bufferSize length of the circular buffer. The given buffer should have
+ * a size greater or equal to this value.
+ */
+void cb_Init(cb_CircularBuffer* cb, uint8_t *buffer, uint16_t bufferSize)
+{
+ cb->buffer = buffer;
+ cb->bufferSize = bufferSize;
+ cb->readIndex = 0;
+ cb->writeIndex = 0;
+}
+
+/**
+ * @brief Gets the number of bytes stored in the queue.
+ * @param cb the cb_CircularBuffer to check.
+ * @return the number of bytes stored in the queue.
+ */
+uint16_t cb_ItemsCount(cb_CircularBuffer* cb)
+{
+ if (cb->writeIndex >= cb->readIndex)
+ return cb->writeIndex - cb->readIndex;
+ else
+ return cb->bufferSize - cb->readIndex + cb->writeIndex;
+}
+
+/**
+ * @brief Check if the queue is empty.
+ * @param cb the cb_CircularBuffer to check.
+ * @return 1 if there are no bytes stored in the queue, 0 otherwise.
+ */
+bool cb_IsEmpty(cb_CircularBuffer* cb)
+{
+ return cb->writeIndex == cb->readIndex;
+}
+
+/**
+ * @brief Check if the queue is full.
+ * @param cb the cb_CircularBuffer to check.
+ * @return 1 if the queue is full, 0 otherwise.
+ */
+bool cb_IsFull(cb_CircularBuffer* cb)
+{
+ if (cb->writeIndex == cb->readIndex)
+ return false;
+ else if (cb->readIndex < cb->writeIndex)
+ return (cb->readIndex == 0 && cb->writeIndex == cb->bufferSize - 1);
+ else
+ return (cb->writeIndex == cb->readIndex-1);
+}
+
+/**
+ * @brief Add a item at the back of the queue.
+ * @param cb the cb_CircularBuffer to affect.
+ * @param newElem the byte to add to the back of the queue.
+ * @warning If the queue is already full, this function does nothing if
+ * CPU_TRAPS_ENABLED is 0. If CPU_TRAPS_ENABLED is 1, this function will block
+ * forever the program execution, so the problem can be found with the
+ * debugger.
+ */
+void cb_Push(cb_CircularBuffer* cb, uint8_t newElem)
+{
+ if (!cb_IsFull(cb)) // Not full.
+ {
+ cb->buffer[cb->writeIndex] = newElem;
+ cb->writeIndex++;
+
+ if (cb->writeIndex >= cb->bufferSize)
+ cb->writeIndex = 0;
+ }
+ else // Error, can't push an item, because the queue is full.
+ utils_TrapCpu();
+}
+
+/**
+ * @brief Extract the item at the front of the queue.
+ * Returns the value of the item at the front of the queue, and remove this item
+ * from the queue.
+ * @param cb the cb_CircularBuffer to affect.
+ * @return the value of the byte that has been extracted from the queue.
+ * @warning If the queue is empty and CPU_TRAPS_ENABLED is 0, this function
+ * returns 0. If CPU_TRAPS_ENABLED is 1, this function will block forever the
+ * program execution, so the problem can be found with the debugger.
+ */
+uint8_t cb_Pull(cb_CircularBuffer* cb)
+{
+ if (cb->writeIndex != cb->readIndex) // Not empty.
+ {
+ uint8_t pulled = cb->buffer[cb->readIndex];
+ cb->readIndex++;
+
+ if (cb->readIndex >= cb->bufferSize)
+ cb->readIndex = 0;
+
+ return pulled;
+ }
+ else // Error, can't pull an item, because the queue is empty.
+ {
+ utils_TrapCpu();
+ return 0;
+ }
+}
diff --git a/Firmware/src/lib/circular_buffer.h b/Firmware/src/lib/circular_buffer.h
new file mode 100644
index 0000000..5d628ba
--- /dev/null
+++ b/Firmware/src/lib/circular_buffer.h
@@ -0,0 +1,40 @@
+#ifndef __CIRCULAR_BUFFER_H
+#define __CIRCULAR_BUFFER_H
+
+#include "../main.h"
+
+/** @defgroup CircularBuffer Circular buffer
+ * @brief Bytes queue (FIFO) implemented with a circular buffer.
+ *
+ * This bytes container works as a queue, which means "first in, first out".
+ * Create a cb_CircularBuffer structure, and initialize it with cb_Init().
+ * Then, add bytes using cb_Push(), and extract them with cb_Pull().
+ *
+ * @ingroup Lib
+ * @addtogroup CircularBuffer
+ * @{
+ */
+
+/**
+ * @brief Circular buffer structure.
+ */
+typedef struct
+{
+ uint8_t *buffer; ///< Pointer to the byte buffer.
+ uint16_t bufferSize; ///< Size of buffer.
+ volatile uint16_t readIndex, ///< Index of the element at the front of the queue.
+ writeIndex; ///< Index of the next free location at the end of the queue.
+} cb_CircularBuffer;
+
+void cb_Init(cb_CircularBuffer* cb, uint8_t *buffer, uint16_t bufferSize);
+uint16_t cb_ItemsCount(cb_CircularBuffer* cb);
+bool cb_IsEmpty(cb_CircularBuffer* cb);
+bool cb_IsFull(cb_CircularBuffer* cb);
+void cb_Push(cb_CircularBuffer* cb, uint8_t newElem);
+uint8_t cb_Pull(cb_CircularBuffer* cb);
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/Firmware/src/lib/utils.c b/Firmware/src/lib/utils.c
index 3a1a5f5..2b8ac8b 100644
--- a/Firmware/src/lib/utils.c
+++ b/Firmware/src/lib/utils.c
@@ -1,87 +1,99 @@
#include "utils.h"
+/**
+ * @brief Endless loop function to stop the execution of the program here.
+ * @note This function does nothing if CPU_TRAPS_ENABLED is set to zero.
+ */
+void utils_TrapCpu(void)
+{
+#if CPU_TRAPS_ENABLED
+ while(1)
+ ;
+#endif
+}
+
/**
* @brief "Busy wait" delay function
* @param duration: Delay time in [us] (approximative value based on a 168MHz core clock)
*/
void utils_DelayUs(uint32_t duration)
{
uint32_t i = 0;
uint32_t j = 0;
for(i=0; i<=duration; i++)
{
for(j=0; j<=26; j++)
{
__asm{NOP};
__asm{NOP};
}
}
}
/**
* @brief "Busy wait" delay function
* @param duration: Delay time in [ms] (approximative value based on a 168MHz core clock).
* @note This delay is approximative, and may last longer if there are many interrupts.
*/
void utils_DelayMs(uint32_t duration)
{
uint32_t i = 0;
uint32_t j = 0;
for(i=0; i<=duration; i++)
{
for(j=0; j<=33600; j++)
{
__asm{NOP};
}
}
}
/**
* @brief Saturate a float number between two bounds.
* @param val: value to constrain between two limits.
* @param min: minimum
* @param max: maximum
* @retval None.
*/
void utils_SaturateF(float32_t *val, float32_t min, float32_t max)
{
if(*val < min)
*val = min;
else if(*val > max)
*val = max;
}
/**
* @brief Saturate an integer number between two bounds.
* @param val: value to constrain between the two limits.
* @param min: lower limit.
* @param max: upper limit.
* @retval None.
*/
void utils_SaturateU(uint32_t *val, uint32_t min, uint32_t max)
{
if(*val < min)
*val = min;
else if(*val > max)
*val = max;
}
/**
* @brief Compute the mean of the array values.
* @param array: array of float number to get the mean from.
* @param size: size of the array.
* @retval the mean of the array values.
*/
float32_t utils_Mean(float32_t *array, int size)
{
int i;
float32_t sum = 0.0f;
for(i=0; i
+#include
#include "arm_math.h"
// Clocks configuration.
#define APB1_PRESCALER 4
#define APB2_PRESCALER 2
#define TIM_MULTIPLIER 2
// Interupt priority.
#define CURRENT_LOOP_IRQ_PRIORITY 1 // High freq loop, should not be interrupted.
#define CONTROL_LOOP_IRQ_PRIORITY 2
#define CODER_INDEX_IRQ_PRIORITY 2 // Useless, remove?
#define UART_RX_IRQ_PRIORIY 3
#define DATA_LOOP_IRQ_PRIORITY 4 // Streaming packets, lowest priority.
// Electrical parameters.
#define STM_SUPPLY_VOLTAGE 3.3f // [V].
#define H_BRIDGE_SUPPLY_VOLTAGE 24.0f // [V].
#define CURRENT_SHUNT_RESISTANCE 0.01f // [ohm].
#define CURRENT_SHUNT_AMPLIFIER_GAIN 50 // [].
#define MOTOR_RESISTANCE 10.6f + 5.0f // 10.6 ohm according to the datasheet, actually more, depends on the motor [ohm].
// Mechanical parameters.
#define REDUCTION_RATIO 16.5f
#define MOTOR_TORQUE_CONST 0.0538f // [N.m/A].
// Status register bit list.
#define STREG_0 ((uint32_t)0x00000001)
#define STREG_1 ((uint32_t)0x00000002)
#define REF_POS_INIT ((uint32_t)0x00000004) // 1 -> Ref position succesfully found
#define CALIBRE ((uint32_t)0x00000008) // 1 -> Calibration done
#define RUN_CURRENT_LOOP ((uint32_t)0x00000010) // 1 -> Current loop active (if motorDrv eneable but RUN_CURRENT_LOOP=false -> fixed 50% PWM on the motor)
#define UN_CONTROL_LOOP ((uint32_t)0x00000020) // 1 -> Control loop active
#define STREG_6 ((uint32_t)0x00000040)
#define STREG_7 ((uint32_t)0x00000080)
#define STREG_8 ((uint32_t)0x00000100)
#define DATA_UPSTREAM_ENB ((uint32_t)0x00000200) // 1 -> data upstream active
#define STREG_10 ((uint32_t)0x00000400)
#define RX_COMPLETED ((uint32_t)0x00000800) // 1 -> packet recieved
#define RX_ERROR ((uint32_t)0x00001000) // 1 -> last received packet incorrect
#define PROCESSING_REQUEST ((uint32_t)0x00002000) // 1 -> processing last received packet in progress (can not receive new data)
#define LAST_REQUEST_IGNORED ((uint32_t)0x00004000)
#define STREG_15 ((uint32_t)0x00008000)
#define STREG_16 ((uint32_t)0x00010000)
#define STREG_17 ((uint32_t)0x00020000)
#define STREG_18 ((uint32_t)0x00040000)
#define STREG_19 ((uint32_t)0x00080000)
#define STREG_20 ((uint32_t)0x00100000)
#define STREG_21 ((uint32_t)0x00200000)
#define STREG_22 ((uint32_t)0x00400000)
#define STREG_23 ((uint32_t)0x00800000)
#define INDEX_ERROR ((uint32_t)0x01000000) // 1 -> wrong step count over 1 rotation
#define STREG_25 ((uint32_t)0x02000000)
#define STREG_26 ((uint32_t)0x04000000)
#define STREG_27 ((uint32_t)0x08000000)
#define STREG_28 ((uint32_t)0x10000000)
#define STREG_29 ((uint32_t)0x20000000)
#define STREG_30 ((uint32_t)0x40000000)
#define STREG_31 ((uint32_t)0x80000000)
#endif