diff --git a/Firmware/carteHRI.uvoptx b/Firmware/carteHRI.uvoptx
index f524f98..09df35f 100644
--- a/Firmware/carteHRI.uvoptx
+++ b/Firmware/carteHRI.uvoptx
@@ -1,747 +1,773 @@
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 -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
uart_txBuffer[0]
1
1
uart_txBuffer[1]
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
+
+ 4
+ 26
+ 1
+ 0
+ 0
+ 0
+ 0
+ .\src\drivers\led.c
+ led.c
+ 0
+ 0
+
+
+ 4
+ 27
+ 1
+ 0
+ 0
+ 0
+ 0
+ .\src\drivers\debug_gpio.c
+ debug_gpio.c
+ 0
+ 0
+
SRC_lib
1
0
0
0
5
- 26
+ 28
1
0
0
0
0
.\src\lib\basic_filter.c
basic_filter.c
0
0
5
- 27
+ 29
1
0
0
0
0
.\src\lib\pid.c
pid.c
0
0
5
- 28
+ 30
1
0
0
0
0
.\src\lib\utils.c
utils.c
0
0
5
- 29
+ 31
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 a59f0aa..de48bfb 100644
--- a/Firmware/carteHRI.uvprojx
+++ b/Firmware/carteHRI.uvprojx
@@ -1,586 +1,596 @@
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
+
+ led.c
+ 1
+ .\src\drivers\led.c
+
+
+ debug_gpio.c
+ 1
+ .\src\drivers\debug_gpio.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 afe9546..09a0263 100644
--- a/Firmware/src/communication.c
+++ b/Firmware/src/communication.c
@@ -1,713 +1,713 @@
#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
uint32_t selectedVariablesToStream; // Bitfield that indicates for each variable if it should be streamed or not.
uint8_t txBuffer[1024];
-#define COMM_BUFFER_SIZE 1024
+#define COMM_BUFFER_SIZE 4096
#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).
// SyncVar-related vars.
#define N_SYNCVARS_MAX 50
comm_SyncVar comm_syncVars[N_SYNCVARS_MAX];
uint8_t comm_nSyncVars;
volatile bool comm_varListLocked;
uint8_t comm_streamId;
uint8_t comm_nVarsToStream;
comm_SyncVar const* comm_streamedVars[N_SYNCVARS_MAX];
extern volatile uint32_t ctrl_timestamp; // [us].
// Private functions.
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);
void comm_SendVarsList(void);
/**
* @brief Init the communication manager.
*/
void comm_Init(void)
{
comm_nSyncVars = 0;
comm_varListLocked = false;
comm_streamId = 0;
comm_nVarsToStream = 0;
// Setup the UART peripheral, and specify the function that will be called
// each time a byte is received.
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));
}
void comm_NotifyReady(void)
{
comm_SendPacket(STM_MESSAGE_START_INFO, NULL, 0);
}
/**
* @brief UART data streaming "loop" function.
*/
void comm_Stream()
{
// If the data streaming is enabled, send a stream packet to the PC.
if(comm_nVarsToStream > 0)
{
uint8_t i;
int nDataBytesToSend = 0;
// Stream ID.
txBuffer[nDataBytesToSend] = comm_streamId;
nDataBytesToSend++;
// Timestamp.
memcpy(&txBuffer[nDataBytesToSend], (uint32_t*)&ctrl_timestamp,
sizeof(ctrl_timestamp));
nDataBytesToSend += sizeof(ctrl_timestamp);
// SyncVars values.
for(i=0; iaddress, sv->size);
nDataBytesToSend += sv->size;
}
comm_SendPacket(STM_MESSAGE_STREAMING_PACKET, txBuffer, nDataBytesToSend);
}
}
/**
* @brief Sends Packet with a header and data bytes.
* @param type: message type ("header" of the message).
* @param data: array of data bytes to be sent ("content" of the message).
* @param dataLength: number of data bytes to be sent.
*/
void comm_SendPacket(uint8_t type, uint8_t *data, uint16_t dataLength)
{
int i=0;
uint8_t *p = comm_packetTxBuffer;
*p = ((1<<7) | type);
p++;
for(i=0; i> 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_PING:
if(dataBytesReady == 0)
comm_SendPacket(STM_MESSAGE_PINGBACK, NULL, 0);
break;
case PC_MESSAGE_GET_VARS_LIST:
if(dataBytesReady == 0 && comm_varListLocked)
{
int16_t i, length;
uint8_t *p = &txBuffer[0];
*p = (uint8_t)comm_nSyncVars;
p++;
for(i=0; i= comm_nSyncVars)
return;
v = &comm_syncVars[variableIndex];
// If the variable is not readable, ignore the request.
if((v->usesVarAddress && v->access == WRITEONLY) ||
(!v->usesVarAddress && v->getFunc == NULL))
{
break;
}
// Prepare the message to be sent to the PC.
// First byte: variable index.
txBuffer[0] = variableIndex;
// Following bytes: actual value of the variable.
if(v->usesVarAddress)
{
v = &comm_syncVars[variableIndex];
memcpy(&txBuffer[1], v->address, v->size);
}
else
{
switch(v->type)
{
case BOOL:
{
bool tmpBool = ((bool (*)(void))v->getFunc)();
memcpy(&txBuffer[1], &tmpBool, v->size);
}
break;
case UINT8:
{
uint8_t tmpUint8 = ((uint8_t (*)(void))v->getFunc)();
memcpy(&txBuffer[1], &tmpUint8, v->size);
}
break;
case INT8:
{
int8_t tmpInt8 = ((int8_t (*)(void))v->getFunc)();
memcpy(&txBuffer[1], &tmpInt8, v->size);
}
break;
case UINT16:
{
uint16_t tmpUint16 = ((uint16_t (*)(void))v->getFunc)();
memcpy(&txBuffer[1], &tmpUint16, v->size);
}
break;
case INT16:
{
int16_t tmpInt16 = ((int16_t (*)(void))v->getFunc)();
memcpy(&txBuffer[1], &tmpInt16, v->size);
}
break;
case UINT32:
{
uint32_t tmpUint32 = ((uint32_t (*)(void))v->getFunc)();
memcpy(&txBuffer[1], &tmpUint32, v->size);
}
break;
case INT32:
{
int32_t tmpInt32 = ((int32_t (*)(void))v->getFunc)();
memcpy(&txBuffer[1], &tmpInt32, v->size);
}
break;
case UINT64:
{
uint32_t tmpUint64 = ((uint64_t (*)(void))v->getFunc)();
memcpy(&txBuffer[1], &tmpUint64, v->size);
}
break;
case INT64:
{
int32_t tmpInt64 = ((int64_t (*)(void))v->getFunc)();
memcpy(&txBuffer[1], &tmpInt64, v->size);
}
break;
case FLOAT32:
{
float32_t tmpFloat = ((float32_t (*)(void))v->getFunc)();
memcpy(&txBuffer[1], &tmpFloat, v->size);
}
break;
case FLOAT64:
{
double tmpDouble = ((double (*)(void))v->getFunc)();
memcpy(&txBuffer[1], &tmpDouble, v->size);
}
break;
}
}
// Send the message to the PC.
comm_SendPacket(STM_MESSAGE_VAR, txBuffer, 1 + v->size);
}
break;
case PC_MESSAGE_SET_VAR:
if(dataBytesReady >= 1)
{
comm_SyncVar *v;
uint8_t variableIndex;
// Extract the index (that indicates which variable will change),
// and the new value of the variable.
variableIndex = rxDataBytesBuffer[0];
// If the variable index is out of range, ignore the request.
if(variableIndex >= comm_nSyncVars)
return;
v = &comm_syncVars[variableIndex];
// Set the selected variable with the new value.
if(dataBytesReady == 1 + v->size)
{
if(v->usesVarAddress)
{
if(v->access != READONLY)
{
v = &comm_syncVars[variableIndex];
memcpy(v->address, &rxDataBytesBuffer[1], v->size);
}
}
else
{
if(v->setFunc == NULL)
break;
switch(v->type)
{
case BOOL:
{
bool tmp;
memcpy(&tmp, &rxDataBytesBuffer[1], v->size);
((void (*)(bool))v->setFunc)(tmp);
}
break;
case UINT8:
{
uint8_t tmp;
memcpy(&tmp, &rxDataBytesBuffer[1], v->size);
((void (*)(uint8_t))v->setFunc)(tmp);
}
break;
case INT8:
{
int8_t tmp;
memcpy(&tmp, &rxDataBytesBuffer[1], v->size);
((void (*)(int8_t))v->setFunc)(tmp);
}
break;
case UINT16:
{
uint16_t tmp;
memcpy(&tmp, &rxDataBytesBuffer[1], v->size);
((void (*)(uint16_t))v->setFunc)(tmp);
}
break;
case INT16:
{
int16_t tmp;
memcpy(&tmp, &rxDataBytesBuffer[1], v->size);
((void (*)(int16_t))v->setFunc)(tmp);
}
break;
case UINT32:
{
uint32_t tmp;
memcpy(&tmp, &rxDataBytesBuffer[1], v->size);
((void (*)(uint32_t))v->setFunc)(tmp);
}
break;
case INT32:
{
int32_t tmp;
memcpy(&tmp, &rxDataBytesBuffer[1], v->size);
((void (*)(int32_t))v->setFunc)(tmp);
}
break;
case UINT64:
{
uint64_t tmp;
memcpy(&tmp, &rxDataBytesBuffer[1], v->size);
((void (*)(uint64_t))v->setFunc)(tmp);
}
break;
case INT64:
{
int64_t tmp;
memcpy(&tmp, &rxDataBytesBuffer[1], v->size);
((void (*)(int64_t))v->setFunc)(tmp);
}
break;
case FLOAT32:
{
float32_t tmp;
memcpy(&tmp, &rxDataBytesBuffer[1], v->size);
((void (*)(float32_t))v->setFunc)(tmp);
}
break;
case FLOAT64:
{
double tmp;
memcpy(&tmp, &rxDataBytesBuffer[1], v->size);
((void (*)(double))v->setFunc)(tmp);
}
break;
}
}
}
}
break;
case PC_MESSAGE_SET_STREAMED_VAR:
if(dataBytesReady >= 1)
{
int i;
comm_nVarsToStream = rxDataBytesBuffer[0];
if(dataBytesReady != 1 + 1 + comm_nVarsToStream)
return;
comm_streamId = rxDataBytesBuffer[1];
for(i=0; i SYNCVAR_NAME_SIZE - 1)
{
memcpy(v.name, name, SYNCVAR_NAME_SIZE - 1);
v.name[SYNCVAR_NAME_SIZE - 1] = '\0';
}
else
strcpy(v.name, name);
//
v.address = address;
v.type = type;
v.size = size;
v.access = access;
v.usesVarAddress = true;
// Add the SyncVar to the list.
comm_syncVars[comm_nSyncVars] = v;
comm_nSyncVars++;
}
}
void comm_monitorVarFunc(const char name[], comm_VarType type, uint8_t size,
void (*getFunc)(void), void (*setFunc)(void))
{
// Adding a variable to the list is not allowed if it has been locked.
if(!comm_varListLocked)
{
comm_SyncVar v;
// Trim the name if it is too long.
if(strlen(name) > SYNCVAR_NAME_SIZE - 1)
{
memcpy(&v.name, &name, SYNCVAR_NAME_SIZE - 1);
v.name[SYNCVAR_NAME_SIZE - 1] = '\0';
}
else
strcpy(v.name, name);
//
v.getFunc = getFunc;
v.setFunc = setFunc;
v.type = type;
v.size = size;
v.usesVarAddress = false;
// Determine the variable access.
if(getFunc != NULL && setFunc == NULL)
v.access = READONLY;
else if(getFunc == NULL && setFunc != NULL)
v.access = WRITEONLY;
else if(getFunc != NULL && setFunc != NULL)
v.access = READWRITE;
else
return; // No function provided at all, ignoring var.
// Add the SyncVar to the list.
comm_syncVars[comm_nSyncVars] = v;
comm_nSyncVars++;
}
}
void comm_monitorBool(const char name[], bool *address,
comm_VarAccess access)
{
comm_monitorVar(name, address, BOOL, 1, access);
}
void comm_monitorUint8(const char name[], uint8_t *address,
comm_VarAccess access)
{
comm_monitorVar(name, address, UINT8, 1, access);
}
void comm_monitorInt8(const char name[], int8_t *address,
comm_VarAccess access)
{
comm_monitorVar(name, address, INT8, 1, access);
}
void comm_monitorUint16(const char name[], uint16_t *address,
comm_VarAccess access)
{
comm_monitorVar(name, address, UINT16, 2, access);
}
void comm_monitorInt16(const char name[], int16_t *address,
comm_VarAccess access)
{
comm_monitorVar(name, address, INT16, 2, access);
}
void comm_monitorUint32(const char name[], uint32_t *address,
comm_VarAccess access)
{
comm_monitorVar(name, address, UINT32, 4, access);
}
void comm_monitorInt32(const char name[], int32_t *address,
comm_VarAccess access)
{
comm_monitorVar(name, address, INT32, 4, access);
}
void comm_monitorUint64(const char name[], uint64_t *address,
comm_VarAccess access)
{
comm_monitorVar(name, address, UINT64, 8, access);
}
void comm_monitorInt64(const char name[], int64_t *address,
comm_VarAccess access)
{
comm_monitorVar(name, address, INT64, 8, access);
}
void comm_monitorFloat(const char name[], float *address,
comm_VarAccess access)
{
comm_monitorVar(name, address, FLOAT32, 4, access);
}
void comm_monitorDouble(const char name[], double *address,
comm_VarAccess access)
{
comm_monitorVar(name, address, FLOAT64, 8, access);
}
void comm_monitorBoolFunc(const char name[],
bool (*getFunc)(void), void (*setFunc)(bool))
{
comm_monitorVarFunc(name, BOOL, 1, (void (*)(void))getFunc, (void (*)(void))setFunc);
}
void comm_monitorUint8Func(const char name[],
uint8_t (*getFunc)(void), void (*setFunc)(uint8_t))
{
comm_monitorVarFunc(name, UINT8, 1, (void (*)(void))getFunc, (void (*)(void))setFunc);
}
void comm_monitorInt8Func(const char name[],
int8_t (*getFunc)(void), void (*setFunc)(int8_t))
{
comm_monitorVarFunc(name, INT8, 1, (void (*)(void))getFunc, (void (*)(void))setFunc);
}
void comm_monitorUint16Func(const char name[],
uint16_t (*getFunc)(void),
void (*setFunc)(uint16_t))
{
comm_monitorVarFunc(name, UINT16, 2, (void (*)(void))getFunc, (void (*)(void))setFunc);
}
void comm_monitorInt16Func(const char name[],
int16_t (*getFunc)(void), void (*setFunc)(int16_t))
{
comm_monitorVarFunc(name, INT16, 2, (void (*)(void))getFunc, (void (*)(void))setFunc);
}
void comm_monitorUint32Func(const char name[],
uint32_t (*getFunc)(void),
void (*setFunc)(uint32_t))
{
comm_monitorVarFunc(name, UINT32, 4, (void (*)(void))getFunc, (void (*)(void))setFunc);
}
void comm_monitorInt32Func(const char name[],
int32_t (*getFunc)(void), void (*setFunc)(int32_t))
{
comm_monitorVarFunc(name, INT32, 4, (void (*)(void))getFunc, (void (*)(void))setFunc);
}
void comm_monitorUint64Func(const char name[],
uint64_t (*getFunc)(void),
void (*setFunc)(uint64_t))
{
comm_monitorVarFunc(name, UINT64, 8, (void (*)(void))getFunc, (void (*)(void))setFunc);
}
void comm_monitorInt64Func(const char name[],
int64_t (*getFunc)(void), void (*setFunc)(int64_t))
{
comm_monitorVarFunc(name, INT64, 8, (void (*)(void))getFunc, (void (*)(void))setFunc);
}
void comm_monitorFloatFunc(const char name[],
float (*getFunc)(void), void (*setFunc)(float))
{
comm_monitorVarFunc(name, FLOAT32, 4, (void (*)(void))getFunc, (void (*)(void))setFunc);
}
void comm_monitorDoubleFunc(const char name[],
double (*getFunc)(void), void (*setFunc)(double))
{
comm_monitorVarFunc(name, FLOAT64, 8, (void (*)(void))getFunc, (void (*)(void))setFunc);
}
void comm_LockSyncVarsList(void)
{
comm_varListLocked = true;
}
void comm_SendVarsList(void)
{
int i;
uint8_t *p;
uint16_t buffLength = 1 + comm_nSyncVars * (SYNCVAR_NAME_SIZE + 1 + 1);
p = &txBuffer[0];
*p = comm_nSyncVars;
p++;
for(i=0; iDR;
DMA_Init(DMA2_Stream1, &DMA_InitStructure);
DMA_Cmd(DMA2_Stream1, ENABLE);
-
}
-
/**
* @brief Compute the current sense offset.
* @note Run before enabling current regulation.
*/
void adc_CalibrateCurrentSens(void)
{
float32_t offset;
int32_t i=0;
for(i=0; iCR2 |= (uint32_t)ADC_CR2_SWSTART;
- else if(channel == ANIN2)
- ADC2->CR2 |= (uint32_t)ADC_CR2_SWSTART;
}
/**
* @brief Get the ADC conversion status of the selected channel.
* @retval 1 if the conversion is finished, 0 otherwise.
*/
uint8_t adc_ConversionIsFinished(AdcChannel channel)
{
if(channel == ANIN1)
return (ADC1->SR & ADC_SR_EOC) != 0;
- else if(channel == ANIN2)
- return (ADC2->SR & ADC_SR_EOC) != 0;
else
return 0;
}
/**
* @brief Get the voltage measured by the selected ADC channel.
* @param channel: the channel of the ADC.
* @param scale: the full scale, depends of the switches position.
* @return the measured voltage, in [V], or 0.0f if the channel is invalid.
* @note make sure that the conversion is finished before calling.
*/
-float32_t adc_GetConversionResult(AdcChannel channel, float32_t scale)
+float32_t adc_GetConversionResult(AdcChannel channel)
{
float32_t adcRawVal, voltage;
if(channel == ANIN1)
adcRawVal = (float32_t)ADC1->DR;
- else if(channel == ANIN2)
- adcRawVal = (float32_t)ADC2->DR;
else
adcRawVal = 0.0f;
- voltage = (1.0f - (adcRawVal / (float32_t)ADC_MAX) * 2.0f) * scale;
+ voltage = (1.0f - (adcRawVal / ADC_MAX) * 2.0f);
return voltage;
}
/**
* @brief Get the voltage measured by the selected ADC channel.
* @param channel: the channel of the ADC.
- * @param scale: the full scale, depends of the switches position.
* @return the measured voltage, in [V], or 0.0f if the channel is invalid.
* @note make sure that the conversion is finished before calling.
*/
-float32_t adc_GetChannelVoltage(AdcChannel channel, float32_t scale)
+float32_t adc_GetChannelVoltage(AdcChannel channel)
{
int32_t conversionTime = 0;
adc_StartConversion(channel);
while(!adc_ConversionIsFinished(channel))
{
if(conversionTime < ADC_MAX_CONVERSION_TIME)
conversionTime++;
else
break;
}
- return adc_GetConversionResult(channel, scale);
+ return adc_GetConversionResult(channel);
}
diff --git a/Firmware/src/drivers/adc.h b/Firmware/src/drivers/adc.h
index 381e6d8..c8542c7 100644
--- a/Firmware/src/drivers/adc.h
+++ b/Firmware/src/drivers/adc.h
@@ -1,78 +1,65 @@
#ifndef __ADC_H
#define __ADC_H
#include "../main.h"
-#define ADC1_Input_Pin GPIO_Pin_4 // Analog diff. input 1
-#define ADC1_Input_Port GPIOC
-#define ADC1_Input_Chan ADC_Channel_14
+#define ADC_HALL_PIN GPIO_Pin_1
+#define ADC_HALL_PORT GPIOB
+#define ADC_HALL_CHANNEL ADC_Channel_9
-#define ADC2_Input_Pin GPIO_Pin_5 // Analog diff. input 2
-#define ADC2_Input_Port GPIOC
-#define ADC2_Input_Chan ADC_Channel_15
-#define ADC_Current_Sens_Pin GPIO_Pin_3 // Current sense channel
-#define ADC_Current_Sens_Port GPIOA
-#define ADC_Current_Sens_Chan ADC_Channel_3
+#define ADC_CURRENT_SENSE_PIN GPIO_Pin_3
+#define ADC_CURRENT_SENSE_PORT GPIOA
+#define ADC_CURRENT_SENSE_CHANNEL ADC_Channel_3
-#define ADC_MAX 4095 // Maximum value of the ADC register (2^12 - 1).
+#define ADC_MAX 4095.0f // Maximum value of the ADC register (2^12 - 1).
#define ADC_MAX_CONVERSION_TIME 100 // To avoid locking if the conversion was not started properly.
#define ADC_BUFFER_SIZE 33 // Fadc =~300kHz -> TE_ADC = 3.33us -> Average over 32 sample => usable bandwidth <10kHz
-#define ADC_CURRENT_SCALE (STM_SUPPLY_VOLTAGE / (CURRENT_SHUNT_RESISTANCE * CURRENT_SHUNT_AMPLIFIER_GAIN * ADC_MAX)) // Scale between ADC increment and current [A/incr].
+#define ADC_CURRENT_SCALE (ADC_REF_VOLTAGE / (CURRENT_SHUNT_RESISTANCE * CURRENT_SHUNT_AMPLIFIER_GAIN * ADC_MAX)) // Scale between ADC increment and current [A/incr].
#define ADC_CALIB_N_SAMPLES 1000
/** @defgroup ADC Driver / ADC
* @brief Driver for the analog-to-digital peripheral of the STM32.
*
* An analog-to-digital converter (ADC) is used to measure the voltage of one
* or several microcontroller pins. In the HRI board, there are two pins that
* can be used. An intermediate electronic stage allows to modify the input
* range from +-33mV to +-10V, in order to get the best sensitivity and range
* for a wide range of analog sensors. Note that the input connector
* (J2-ANALOG IN) provides differential inputs, so one pair of pins per
* channel.
*
* In addition, there is an additional channel to measure the current going
* through the motor (useful for current regulation).
*
* Call adc_Init() first, in the initialization code. Then, call
* adc_GetChannelVoltage() every time you need the voltage.
*
* To measure accurately the motor current, a calibration has to be performed
* first. Call dc_CalibrateCurrentSens() in the main(), when the current
* regulation is disabled (see H-bridge documentation). Then, call
* adc_GetCurrent() every time it is needed. This function returns the last
* value transfered by the DMA, so there is no conversion delay when calling
* this function.
*
* @addtogroup ADC
* @{
*/
-// Switches-selectable scale of the ADC circuit.
-// Could be useful to perform a calibration, to precise readings.
-#define ADC_SCALE_0_033_V 0.033f ///< +-33mV, switches position: 0100
-#define ADC_SCALE_0_165_V 0.165f ///< +-165mV, switches position: 0010
-#define ADC_SCALE_0_400_V 0.400f ///< +-400mV, switches position: 1100
-#define ADC_SCALE_0_830_V 0.830f ///< +-830mV, switches position: 0001
-#define ADC_SCALE_2_V 2.000f ///< +-2V, switches position: 1010
-#define ADC_SCALE_10_V 10.00f ///< +-10V, switches position: 1001
-
/**
* @brief Enum that corresponds to the two ADC input channels of the board.
*/
typedef enum
{
- ANIN1=1, ///< Channel 1, pins ANIN1+ (3) and ANIN1- (4) of the connector J2.
- ANIN2=2 ///< Channel 2, pins ANIN2+ (7) and ANIN2- (8) of the connector J2.
+ ANIN1=1 ///< Channel 1, pins ANIN1+ (3) and ANIN1- (4) of the connector J2.
} AdcChannel;
void adc_Init(void);
void adc_CalibrateCurrentSens(void);
float32_t adc_GetCurrent(void); // [mA].
-float32_t adc_GetChannelVoltage(AdcChannel channel, float32_t scale);
+float32_t adc_GetChannelVoltage(AdcChannel channel);
/**
* @}
*/
#endif
diff --git a/Firmware/src/drivers/callback_timers.c b/Firmware/src/drivers/callback_timers.c
index 697cf50..0139740 100644
--- a/Firmware/src/drivers/callback_timers.c
+++ b/Firmware/src/drivers/callback_timers.c
@@ -1,227 +1,227 @@
#include "callback_timers.h"
#include "../controller.h"
#include "../lib/utils.h"
-cbt_PeriodicTaskFunc cbt_tim1Task, cbt_tim6Task, cbt_tim7Task;
+cbt_PeriodicTaskFunc cbt_tim10Task, cbt_tim6Task, cbt_tim7Task;
volatile float32_t cbt_ucLoad; // Processor load (%).
-void tim1InitFunc(void);
+void tim10InitFunc(void);
void tim67InitFunc(void);
/**
* @brief Initialize the timers to call an interrupt routine periodically.
*/
void cbt_Init(void)
{
// Initialize the timers.
- tim1InitFunc();
+ tim10InitFunc();
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_tim10Task = 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;
+ cbt_tim10Task = f;
utils_SaturateU(&period, TE_LOOP_MIN_VALUE, TE_LOOP_MAX_VALUE);
- TIM1->ARR = (uint16_t) period;
+ TIM10->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).
+ * @brief Initialize TIM10 used for timing the current loop (resolution 1us).
*/
-void tim1InitFunc(void)
+void tim10InitFunc(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
//TIM_OCInitTypeDef TIM_OCInitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM10, 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_Prescaler = TIM10_PRESCALER;
TIM_TimeBaseStruct.TIM_ClockDivision = 0; // TIM_CKD_DIV2;
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
- TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStruct);
+ TIM_TimeBaseInit(TIM10, &TIM_TimeBaseStruct);
- TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
- TIM_Cmd(TIM1, ENABLE);
+ TIM_ITConfig(TIM10, TIM_IT_Update, ENABLE);
+ TIM_Cmd(TIM10, 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, ENABLE);
}
/**
- * @brief Interrupt from current control loop timer (TIM1)
+ * @brief Interrupt from current control loop timer (TIM10)
*/
void TIM1_UP_TIM10_IRQHandler(void)
{
- if(TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET)
+ if(TIM_GetITStatus(TIM10, TIM_IT_Update) != RESET)
{
- if(cbt_tim1Task != NULL)
- cbt_tim1Task();
+ if(cbt_tim10Task != NULL)
+ cbt_tim10Task();
- TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
+ TIM_ClearITPendingBit(TIM10, 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;
+ return TIM10->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/callback_timers.h b/Firmware/src/drivers/callback_timers.h
index 2fe70e0..bb6610e 100644
--- a/Firmware/src/drivers/callback_timers.h
+++ b/Firmware/src/drivers/callback_timers.h
@@ -1,44 +1,43 @@
#ifndef __CALLBACK_TIMERS_H
#define __CALLBACK_TIMERS_H
#include "../main.h"
typedef void (*cbt_PeriodicTaskFunc)(void);
// TIMX_PERIOD is the clock divider at the input of the timers.
// So, the timer will increment its counter, every TIMX_PERIOD ticks of the system clock (168 MHz).
-// For example, current loop: TIM1_PRESCALER=168 => TIM1 will have a frequency of (168MHz/168=) 1MHz => 1 us.
-#define TIM1_PRESCALER ((uint16_t)(SystemCoreClock/APB2_PRESCALER*TIM_MULTIPLIER/1000000-1)) // CLK_CNT = 1[us] (current loop)
+#define TIM10_PRESCALER ((uint16_t)(SystemCoreClock/APB2_PRESCALER*TIM_MULTIPLIER/1000000-1)) // CLK_CNT = 1[us] (current loop)
#define TIM6_PRESCALER ((uint16_t)(SystemCoreClock/APB1_PRESCALER*TIM_MULTIPLIER/1000000-1)) // CLK_CNT = 1[us] (control loop)
#define TIM7_PRESCALER ((uint16_t)(SystemCoreClock/APB1_PRESCALER*TIM_MULTIPLIER/1000000-1)) // CLK_CNT = 1[us] (data loop)
/** @defgroup CallbackTimers Driver / Callback timers
* @brief Driver to call functions at a fixed rate.
*
* This driver setups three timers of the STM32, in order to call at a precise
* rate the control functions: the current regulation loop, the position
* regulation loop and the communication loop (data streaming part only).
*
* In the initialization code, first call cbt_Init(). Then call each
* cbt_Set*LoopTimer() function, giving the pointer to the function to call as
* an argument.
*
* @addtogroup CallbackTimers
* @{
*/
void cbt_Init(void);
void cbt_SetCurrentLoopTimer(cbt_PeriodicTaskFunc f, uint32_t period);
void cbt_SetPositionLoopTimer(cbt_PeriodicTaskFunc f, uint32_t period);
void cbt_SetCommLoopTimer(cbt_PeriodicTaskFunc f, uint32_t period);
void cbt_SetPositionLoopPeriod(uint32_t period);
void cbt_SetCommLoopPeriod(uint32_t period);
uint32_t cbt_GetCurrentLoopPeriod(void);
uint32_t cbt_GetPositionLoopPeriod(void);
uint32_t cbt_GetCommLoopPeriod(void);
/**
* @}
*/
#endif
diff --git a/Firmware/src/drivers/debug_gpio.c b/Firmware/src/drivers/debug_gpio.c
new file mode 100644
index 0000000..a0d84cd
--- /dev/null
+++ b/Firmware/src/drivers/debug_gpio.c
@@ -0,0 +1,50 @@
+#include "debug_gpio.h"
+
+#define N_GPIOS 3
+#define DIO_PORT GPIOB
+
+const uint32_t dio_gpios[N_GPIOS] = { GPIO_Pin_14, GPIO_Pin_13, GPIO_Pin_12 };
+
+void dio_Init(void)
+{
+ int i;
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ for(i=0; i= 0 && pinIndex < N_GPIOS)
+ return GPIO_ReadInputDataBit(DIO_PORT, dio_gpios[pinIndex]);
+ else
+ return 0;
+}
+
+void dio_Set(int pinIndex, bool high)
+{
+ if(pinIndex >= 0 && pinIndex < N_GPIOS)
+ {
+ GPIO_WriteBit(DIO_PORT, dio_gpios[pinIndex],
+ high ? Bit_SET : Bit_RESET);
+ }
+}
+
+void dio_Toggle(int pinIndex)
+{
+ if(pinIndex >= 0 && pinIndex < N_GPIOS)
+ {
+ bool newState = !GPIO_ReadInputDataBit(DIO_PORT, dio_gpios[pinIndex]);
+ GPIO_WriteBit(DIO_PORT, dio_gpios[pinIndex],
+ newState ? Bit_SET : Bit_RESET);
+ }
+}
diff --git a/Firmware/src/drivers/debug_gpio.h b/Firmware/src/drivers/debug_gpio.h
new file mode 100644
index 0000000..b7cea01
--- /dev/null
+++ b/Firmware/src/drivers/debug_gpio.h
@@ -0,0 +1,25 @@
+#ifndef __DEBUG_GPIO_H
+#define __DEBUG_GPIO_H
+
+#include "../main.h"
+
+/** @defgroup DGPIO Driver / Debug GPIOs
+ * @brief Driver to control three GPIOs, to debug easily with an oscilloscope.
+ *
+ * Call dio_Init() first in the initialization code. Then, call dio_Set() to
+ * set the GPIO states.
+ *
+ * @addtogroup DGPIO
+ * @{
+ */
+
+void dio_Init(void);
+bool dio_Get(int pinIndex);
+void dio_Set(int pinIndex, bool high);
+void dio_Toggle(int pinIndex);
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/Firmware/src/drivers/hall.c b/Firmware/src/drivers/hall.c
index 82d106a..1f2f22a 100644
--- a/Firmware/src/drivers/hall.c
+++ b/Firmware/src/drivers/hall.c
@@ -1,26 +1,26 @@
#include "hall.h"
AdcChannel hall_channel;
/**
* @brief Initialize the hall sensor driver.
* @param channel: the ADC channel the hall sensor is wired to (0 or 1).
*/
void hall_Init(AdcChannel channel)
{
hall_channel = channel;
}
/**
* @brief Return the measured paddle angle.
* @retval The paddle angle [deg].
* @warning this function is not implemented yet, and returns actually the raw
* voltage from the Hall sensor, instead of the ready-to-use angular position.
*/
float32_t hall_Get(void)
{
- float32_t voltage = adc_GetChannelVoltage(hall_channel, ADC_SCALE_10_V);
+ float32_t voltage = adc_GetChannelVoltage(hall_channel);
// TODO: the voltage to angle conversion is not implemented yet.
return voltage;
}
diff --git a/Firmware/src/drivers/incr_encoder.h b/Firmware/src/drivers/incr_encoder.h
index b83237e..e859d3b 100644
--- a/Firmware/src/drivers/incr_encoder.h
+++ b/Firmware/src/drivers/incr_encoder.h
@@ -1,39 +1,41 @@
#ifndef __INCR_ENCODERS_H
#define __INCR_ENCODERS_H
#include "../main.h"
#define CODER_A_Pin GPIO_Pin_0
#define CODER_A_Port GPIOA
#define CODER_A_PinSource GPIO_PinSource0
+
#define CODER_B_Pin GPIO_Pin_1
#define CODER_B_Port GPIOA
#define CODER_B_PinSource GPIO_PinSource1
-#define CODER_I_Pin GPIO_Pin_1
+
+#define CODER_I_Pin GPIO_Pin_3
#define CODER_I_Port GPIOE
#define CODER_RESOLUTION ((uint32_t)2000) // Number of increments per turn.
/** @defgroup Encoder Driver / Incremental encoder
* @brief Driver for an incremental encoder.
*
* This driver uses a timer of the STM32, configured as a quadrature decoder.
*
* Call enc_Init() first in the initialization code. Then, call enc_GetPosition() to
* get the decoded value.
* The output value is the paddle position in degrees, taking the reduction
* ratio into account.
*
* @addtogroup Encoder
* @{
*/
void enc_Init(void);
float32_t enc_GetPosition(void);
void enc_SetPosition(float32_t newPosition);
/**
* @}
*/
#endif
diff --git a/Firmware/src/drivers/led.c b/Firmware/src/drivers/led.c
new file mode 100644
index 0000000..33aa85a
--- /dev/null
+++ b/Firmware/src/drivers/led.c
@@ -0,0 +1,108 @@
+#include "led.h"
+#include "../communication.h"
+
+#define N_LEDS 4
+
+#define LED_TIMER TIM1
+#define LED_PORT GPIOA
+#define LED_MAX_DUTY 255
+#define LED_PWM_FREQ 32000 // [Hz].
+
+typedef struct
+{
+ uint16_t const pin, pinSource;
+ volatile uint32_t *const duty;
+} led_Led;
+
+led_Led led_leds[N_LEDS] =
+{
+ { GPIO_Pin_8, GPIO_PinSource8, &LED_TIMER->CCR1 },
+ { GPIO_Pin_9, GPIO_PinSource9, &LED_TIMER->CCR2 },
+ { GPIO_Pin_10, GPIO_PinSource10, &LED_TIMER->CCR3 },
+ { GPIO_Pin_11, GPIO_PinSource11, &LED_TIMER->CCR4 },
+};
+
+void setLed0(float32_t brightness) { led_Set(0, brightness); };
+void setLed1(float32_t brightness) { led_Set(1, brightness); };
+void setLed2(float32_t brightness) { led_Set(2, brightness); };
+void setLed3(float32_t brightness) { led_Set(3, brightness); };
+
+float32_t getLed0(void) { return led_Get(0); };
+float32_t getLed1(void) { return led_Get(1); };
+float32_t getLed2(void) { return led_Get(2); };
+float32_t getLed3(void) { return led_Get(3); };
+
+void led_Init(void)
+{
+ int i;
+ GPIO_InitTypeDef GPIO_InitStruct;
+ TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
+ TIM_OCInitTypeDef TIM_OCInitStruct;
+
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
+
+ // Initialize each pin.
+ for(i=0; i= 0 && ledIndex < N_LEDS)
+ return ((float32_t)(*led_leds[ledIndex].duty)) / (float32_t)LED_MAX_DUTY;
+ else
+ return 0.0f;
+}
+
+void led_Set(int ledIndex, float32_t brightness)
+{
+ if(ledIndex >= 0 && ledIndex < N_LEDS &&
+ brightness >= 0.0f && brightness <= 1.0f)
+ {
+ *led_leds[ledIndex].duty = (uint32_t)(brightness * (float32_t)LED_MAX_DUTY);
+ }
+}
diff --git a/Firmware/src/drivers/led.h b/Firmware/src/drivers/led.h
new file mode 100644
index 0000000..e3b6be0
--- /dev/null
+++ b/Firmware/src/drivers/led.h
@@ -0,0 +1,24 @@
+#ifndef __LED_H
+#define __LED_H
+
+#include "../main.h"
+
+/** @defgroup LED Driver / LED
+ * @brief Driver to control a LEDs row.
+ *
+ * Call led_Init() first in the initialization code. Then, call led_Set() to
+ * set the LEDs ON or OFF.
+ *
+ * @addtogroup LED
+ * @{
+ */
+
+void led_Init(void);
+float32_t led_Get(int ledIndex);
+void led_Set(int ledIndex, float32_t brightness);
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/Firmware/src/drivers/strain_gauge.c b/Firmware/src/drivers/strain_gauge.c
index b3beeae..f718a85 100644
--- a/Firmware/src/drivers/strain_gauge.c
+++ b/Firmware/src/drivers/strain_gauge.c
@@ -1,33 +1,33 @@
#include "strain_gauge.h"
#include "dac.h"
#include "../lib/basic_filter.h"
AdcChannel sg_channel;
bfilt_BasicFilter sg_filt;
/**
* @brief Initialize the strain gauge driver.
* @param channel: the ADC channel the strain gauge is wired to (0 or 1).
*/
void sg_Init(AdcChannel channel)
{
sg_channel = channel;
dac_SetVoltage2(2.4f);
bfilt_Init(&sg_filt, 0.1f, 0.0f);
}
/**
* @brief Return the measured force on the paddle.
* @retval The force applied to the top of the paddle [N].
* @warning this function is not implemented yet, and returns actually the raw
* voltage from the sensor, instead of the ready-to-use force.
*/
float32_t sg_Get(void)
{
- float32_t voltage = adc_GetChannelVoltage(sg_channel, ADC_SCALE_0_033_V);
+ float32_t voltage = adc_GetChannelVoltage(sg_channel);
- // TODO: the voltage to angle conversion is not implemented yet.
+ // TODO: the voltage to torque conversion is not implemented yet.
return bfilt_Step(&sg_filt, voltage);
}
diff --git a/Firmware/src/drivers/tachometer.c b/Firmware/src/drivers/tachometer.c
index 7eccd9f..6ddc80d 100644
--- a/Firmware/src/drivers/tachometer.c
+++ b/Firmware/src/drivers/tachometer.c
@@ -1,24 +1,24 @@
#include "tachometer.h"
AdcChannel tac_channel;
/**
* @brief Initialize the tachometer driver.
* @param channel: the ADC channel the tachometer is wired to (0 or 1).
*/
void tac_Init(AdcChannel channel)
{
tac_channel = channel;
}
/**
* @brief Return the measured paddle angular speed.
* @retval The paddle angular speed [deg/s].
*/
float32_t tac_Get(void)
{
- float32_t voltage = adc_GetChannelVoltage(tac_channel, ADC_SCALE_2_V);
+ float32_t voltage = adc_GetChannelVoltage(tac_channel);
// Conversion from voltage to angular speed.
return voltage * TAC_VOLTAGE_TO_RPM;
}
diff --git a/Firmware/src/drivers/uart.c b/Firmware/src/drivers/uart.c
index 48b5fa7..610f46f 100644
--- a/Firmware/src/drivers/uart.c
+++ b/Firmware/src/drivers/uart.c
@@ -1,281 +1,281 @@
#include "uart.h"
#include "../lib/utils.h"
#include "../communication.h" // TODO: REMOVE. DEBUG ONLY.
#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_TX_BUFFER_SIZE 4096
#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 Initializes the UART module.
*/
void uart_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
DMA_InitTypeDef DMA_InitStruct;
// Enable UART and DMA peripherals clocks.
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
// 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);
// Setup the UART peripheral.
USART_InitStruct.USART_BaudRate = UART_BAUDRATE;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
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;
USART_Init(USART_PC_COMM, &USART_InitStruct);
USART_Cmd(USART_PC_COMM, ENABLE);
// Setup the DMA for RX.
DMA_DeInit(UART_RX_DMA);
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_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);
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 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)
{
// 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 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 Starts the DMA transfer to send bytes to UART peripheral.
*/
void uart_StartDma(void)
{
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 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)
{
while(length > 0)
{
uint16_t nBytesToWriteInBuf;
// 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 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/main.c b/Firmware/src/main.c
index b98c26f..72f3ca2 100644
--- a/Firmware/src/main.c
+++ b/Firmware/src/main.c
@@ -1,89 +1,100 @@
#include "main.h"
#include "communication.h"
#include "controller.h"
#include "drivers/adc.h"
#include "drivers/callback_timers.h"
#include "drivers/dac.h"
+#include "drivers/debug_gpio.h"
#include "drivers/h_bridge.h"
#include "drivers/hall.h"
#include "drivers/incr_encoder.h"
+#include "drivers/led.h"
#include "drivers/strain_gauge.h"
#include "drivers/tachometer.h"
#include "lib/utils.h"
extern volatile uint32_t ctrl_timestamp;
volatile uint32_t statusReg = 0x00000000; // Main state register.
/**
* @brief Main function, setups all the drivers and controllers.
*/
int main(void)
{
float demoSineOutput, demoCosineOutput, demoSineAmplitude;
int16_t testInt;
// Setup the GPIOs and the interrupts.
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB |
RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD |
RCC_AHB1Periph_GPIOE, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
//
cbt_Init(); // Setup the timers that will call the loops functions.
adc_Init(); // Setup the ADC.
comm_Init(); // Setup the communication module.
ctrl_Init(); // Setup the controllers.
enc_Init(); // Setup the incremental encoders.
hb_Init(); // Setup the H-bridge.
hb_Enable(); //
dac_Init(); // Setup the DAC.
+ //led_Init();
+ dio_Init();
+
// Delay to let the power electronics stabilize before calibrating the
// current sensor.
utils_DelayMs(200);
adc_CalibrateCurrentSens();
// Start the current loop.
ctrl_StartCurrentLoop();
// Init the external sensors drivers, connected to the ADC.
hall_Init(ANIN1);
//sg_Init(ANIN2);
//tac_Init(ANIN2);
// SyncVar demo with a configurable sine wave.
testInt = 0.0f;
demoSineAmplitude = 1.0f;
comm_monitorFloat("demo_sine_output", &demoSineOutput, READONLY);
comm_monitorFloat("demo_cosine_output", &demoCosineOutput, READONLY);
comm_monitorFloat("demo_sine_amplitude", &demoSineAmplitude, READWRITE);
comm_monitorInt16("demo_test_int", &testInt, READWRITE);
// End of the initialization. Lock the SyncVar list, and notify the PC that
// the board has (re)started.
comm_LockSyncVarsList();
comm_NotifyReady();
// Endless loop. The low priority functions are called here.
while(1)
{
+ //
+ dio_Set(0, true);
+
// Update the communication.
comm_Step();
// SyncVar demo with a configurable sine wave.
demoSineOutput = demoSineAmplitude *
sinf(2.0f*3.14f*((float)ctrl_timestamp) / 1000000.0f
* 0.2f);
demoCosineOutput = demoSineAmplitude *
cosf(2.0f*3.14f*((float)ctrl_timestamp) / 1000000.0f
* 0.2f);
+
+ //
+ dio_Set(0, false);
}
}
diff --git a/Firmware/src/main.h b/Firmware/src/main.h
index 34e6d49..20bc0b3 100644
--- a/Firmware/src/main.h
+++ b/Firmware/src/main.h
@@ -1,62 +1,84 @@
/** \mainpage HRI board firmware documentation
* \section intro_sec Introduction
* This is the documentation of the HRI board firmware. You will find a
* description of the provided library and drivers. As all the hardware and
* software is very new, please do not hesitate to suggest improvements to the
* course assistants (Romain Baud, Philipp Hörler and Laurent Jenni).
*
* \section code_struct_sec Code structure
* The code is divided into 3 parts:
* - main: this is where the controllers and the communication protocol are
* implemented. The call of all the initialization functions is also made here.
* - library: all the algorithms, data structures that could be used at many
* places, are put into the library.
* - drivers: there is one driver per peripheral. All the hardware-specific
- * code is wrapped into these files, so that the user does not have to use a
+ * code is wrapped into these files, so that the user does not have to worry
+ * about the microcontroller operation (and spend a lot of time to read the
+ * documentation).
*
* One module (controller, communication, library or driver) is always splitted
* in two files, .h and .c, like in C++.
* @image html soft_architecture.png
*
* \section lib_how_to How to use the provided library
* For most of the driver/library modules, call x_Init() only once, when the
* program starts (typically in the main()). Then, you can call
* x_Step()/x_Set()/x_Get() everytime as needed, typically in the control
* functions called periodically (ctrl_RegulatePosition()...).
*
* See the "Modules" section of this documentation to see how they work.
+ *
+ * \section stm32_resources_usage STM32's resources usage
+ * \subsection stm32_resources_usage_timers Timers
+ * - TIM1: PWM of the 4 user LEDs.
+ * - TIM2:
+ * - TIM3:
+ * - TIM4:
+ * - TIM5: encoder quadrature decoder.
+ * - TIM6: position loop.
+ * - TIM7: variables streaming loop.
+ * - TIM8: H-bridge PWM.
+ * - TIM9:
+ * - TIM10: current loop.
+ * - TIM11:
+ * - TIM12:
+ * - TIM13:
+ * - TIM14:
*/
#ifndef __MAIN_H
#define __MAIN_H
#include "stm32f4_discovery.h"
#include
#include
#include "arm_math.h"
// Clocks configuration.
+#define STM_SYSCLOCK_FREQ 168000000 // [Hz].
#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 STM_SUPPLY_VOLTAGE 3.3f // Power supply voltage of the microcontroller [V].
+#define ADC_REF_VOLTAGE 2.5f // Voltage reference of the ADC (VREF) [V].
#define H_BRIDGE_SUPPLY_VOLTAGE 24.0f // [V].
-#define CURRENT_SHUNT_RESISTANCE 0.01f // [ohm].
-#define CURRENT_SHUNT_AMPLIFIER_GAIN 50 // [].
+#define CURRENT_SHUNT_RESISTANCE 0.010f // [ohm].
+#define CURRENT_SHUNT_AMPLIFIER_GAIN 50.0f // [].
#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].
+#define MOTOR_SPEED_CONST 177.0f // [RPM/V].
#define MOTOR_NOMINAL_TORQUE 0.0323f // [N.m].
#endif