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