From 52c3517c844d18103dbde2505cc304679a608931 Mon Sep 17 00:00:00 2001 From: Wetmelon Date: Tue, 22 Aug 2017 02:34:31 -0400 Subject: [PATCH 01/35] Slightly improve USB message handling, add quit command --- tools/test_bulk.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/test_bulk.py b/tools/test_bulk.py index 6b348f43..ae81ac03 100644 --- a/tools/test_bulk.py +++ b/tools/test_bulk.py @@ -38,12 +38,17 @@ def main(args): time.sleep(0.1) try: command = input("Enter ODrive command:\n") - dev.send(command) + if 'q' in command: + running = False + sys.exit() + else: + dev.send(command) except: running = False def recieve_thread(dev): global ready + while running: time.sleep(0.1) try: From 28acbedba3e6c3e52be45754ade81612268573fe Mon Sep 17 00:00:00 2001 From: Wetmelon Date: Tue, 22 Aug 2017 02:35:34 -0400 Subject: [PATCH 02/35] Add timeout to USB message reads in python script --- tools/odrive/usbbulk.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/odrive/usbbulk.py b/tools/odrive/usbbulk.py index e2c2d66c..1e430be1 100644 --- a/tools/odrive/usbbulk.py +++ b/tools/odrive/usbbulk.py @@ -110,7 +110,7 @@ class ODriveBulkDevice(): def recieve(self, bufferLen): try: - ret = self.epr.read(bufferLen, 0) + ret = self.epr.read(bufferLen, 100) return ret except usb.core.USBError: #return -1 @@ -120,4 +120,4 @@ class ODriveBulkDevice(): return 64 def recieve_max(self): - return 64 + return 256 From 1596c0acc7ccf4927b995dcf83f090937e5cb505 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 19 Sep 2017 21:38:50 -0400 Subject: [PATCH 03/35] Revert changing receive_max val --- tools/odrive/usbbulk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/odrive/usbbulk.py b/tools/odrive/usbbulk.py index 1e430be1..21898ac5 100644 --- a/tools/odrive/usbbulk.py +++ b/tools/odrive/usbbulk.py @@ -120,4 +120,4 @@ class ODriveBulkDevice(): return 64 def recieve_max(self): - return 256 + return 64 From 47cd3e2a7eadfb3bfba93566d87b87b589f11b5b Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 19 Sep 2017 21:42:08 -0400 Subject: [PATCH 04/35] Correct spelling of "receive" --- tools/odrive/usbbulk.py | 4 ++-- tools/test_bulk.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/odrive/usbbulk.py b/tools/odrive/usbbulk.py index 21898ac5..cdda7641 100644 --- a/tools/odrive/usbbulk.py +++ b/tools/odrive/usbbulk.py @@ -108,7 +108,7 @@ class ODriveBulkDevice(): #return -1 raise - def recieve(self, bufferLen): + def receive(self, bufferLen): try: ret = self.epr.read(bufferLen, 100) return ret @@ -119,5 +119,5 @@ class ODriveBulkDevice(): def send_max(self): return 64 - def recieve_max(self): + def receive_max(self): return 64 diff --git a/tools/test_bulk.py b/tools/test_bulk.py index ae81ac03..8a6d83ec 100644 --- a/tools/test_bulk.py +++ b/tools/test_bulk.py @@ -32,7 +32,7 @@ def main(args): print (dev.info()) print (dev.init()) # thread - thread = threading.Thread(target=recieve_thread, args=[dev]) + thread = threading.Thread(target=receive_thread, args=[dev]) thread.start() while running: time.sleep(0.1) @@ -46,13 +46,13 @@ def main(args): except: running = False -def recieve_thread(dev): +def receive_thread(dev): global ready while running: time.sleep(0.1) try: - message = dev.recieve(dev.recieve_max()) + message = dev.receive(dev.receive_max()) message_ascii = bytes(message).decode('ascii') print(message_ascii, end='') if "ODrive Firmware" in message_ascii: From b097f589f22775ef74699b6720088503cdd90e33 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 19 Sep 2017 21:58:18 -0400 Subject: [PATCH 05/35] Add "Quit" command to script header --- tools/test_bulk.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/test_bulk.py b/tools/test_bulk.py index 8a6d83ec..d48d4b98 100644 --- a/tools/test_bulk.py +++ b/tools/test_bulk.py @@ -26,6 +26,7 @@ def main(args): print("\tPOSITION_CONTROL:\n\t\tp MOTOR_NUMBER POSITION VELOCITY CURRENT") print("\tVELOCITY_CONTROL:\n\t\tv MOTOR_NUMBER VELOCITY CURRENT") print("\tCURRENT_CONTROL:\n\t\tc MOTOR_NUMBER CURRENT") + print("\tQuit Python Script:\n\t\tq") print("---------------------------------------------------------------------") # query device dev = usbbulk.poll_odrive_bulk_device(printer=print) From 49cfc582fab5053c739cde51c6ab103887b4c03c Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 19 Sep 2017 22:08:10 -0400 Subject: [PATCH 06/35] ODrive responds w/ motor # to indicate ctrl msg received --- MotorControl/low_level.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MotorControl/low_level.c b/MotorControl/low_level.c index 83f284f6..2fa994dd 100755 --- a/MotorControl/low_level.c +++ b/MotorControl/low_level.c @@ -422,6 +422,7 @@ void motor_parse_cmd(uint8_t* buffer, int len) { int numscan = sscanf((const char*)buffer, "p %u %f %f %f", &motor_number, &pos_setpoint, &vel_feed_forward, ¤t_feed_forward); if (numscan == 4 && motor_number < num_motors) { set_pos_setpoint(&motors[motor_number], pos_setpoint, vel_feed_forward, current_feed_forward); + printf("M%d\n", motor_number); } } else if (buffer[0] == 'v') { // velocity control @@ -430,6 +431,7 @@ void motor_parse_cmd(uint8_t* buffer, int len) { int numscan = sscanf((const char*)buffer, "v %u %f %f", &motor_number, &vel_feed_forward, ¤t_feed_forward); if (numscan == 3 && motor_number < num_motors) { set_vel_setpoint(&motors[motor_number], vel_feed_forward, current_feed_forward); + printf("M%d\n", motor_number); } } else if (buffer[0] == 'c') { // current control @@ -438,6 +440,7 @@ void motor_parse_cmd(uint8_t* buffer, int len) { int numscan = sscanf((const char*)buffer, "c %u %f", &motor_number, ¤t_feed_forward); if (numscan == 2 && motor_number < num_motors) { set_current_setpoint(&motors[motor_number], current_feed_forward); + printf("M%d\n", motor_number); } } else if (buffer[0] == 'g') { // GET // g <0:float,1:int,2:bool,3:uint16> index From a0a6be6c4d2cacc86f819b97a0426df0005c13da Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 19 Sep 2017 22:08:10 -0400 Subject: [PATCH 07/35] Revert "ODrive responds w/ motor # to indicate ctrl msg received" This reverts commit 49cfc582fab5053c739cde51c6ab103887b4c03c. --- MotorControl/low_level.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/MotorControl/low_level.c b/MotorControl/low_level.c index 2fa994dd..83f284f6 100755 --- a/MotorControl/low_level.c +++ b/MotorControl/low_level.c @@ -422,7 +422,6 @@ void motor_parse_cmd(uint8_t* buffer, int len) { int numscan = sscanf((const char*)buffer, "p %u %f %f %f", &motor_number, &pos_setpoint, &vel_feed_forward, ¤t_feed_forward); if (numscan == 4 && motor_number < num_motors) { set_pos_setpoint(&motors[motor_number], pos_setpoint, vel_feed_forward, current_feed_forward); - printf("M%d\n", motor_number); } } else if (buffer[0] == 'v') { // velocity control @@ -431,7 +430,6 @@ void motor_parse_cmd(uint8_t* buffer, int len) { int numscan = sscanf((const char*)buffer, "v %u %f %f", &motor_number, &vel_feed_forward, ¤t_feed_forward); if (numscan == 3 && motor_number < num_motors) { set_vel_setpoint(&motors[motor_number], vel_feed_forward, current_feed_forward); - printf("M%d\n", motor_number); } } else if (buffer[0] == 'c') { // current control @@ -440,7 +438,6 @@ void motor_parse_cmd(uint8_t* buffer, int len) { int numscan = sscanf((const char*)buffer, "c %u %f", &motor_number, ¤t_feed_forward); if (numscan == 2 && motor_number < num_motors) { set_current_setpoint(&motors[motor_number], current_feed_forward); - printf("M%d\n", motor_number); } } else if (buffer[0] == 'g') { // GET // g <0:float,1:int,2:bool,3:uint16> index From 76b4483323810b4dd5f295512525095cf8304800 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 23 Sep 2017 01:09:32 -0400 Subject: [PATCH 08/35] More detailed USB Communications instructions --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d0cbf037..1b0c8ec1 100644 --- a/README.md +++ b/README.md @@ -108,8 +108,14 @@ If you prefer to debug from eclipse, see [Setting up Eclipse development environ ## Communicating over USB There is currently a very primitive method to read/write configuration, commands and errors from the ODrive over the USB. -Please use the `ODriveFirmware/tools/test_bulk.py` python script for this. -On Windows you need to set the driver for ODrive to libusb using [Zadig](http://zadig.akeo.ie/). +Please use the `ODriveFirmware/tools/test_bulk.py` python script for this. It is written for Python 3. + +Setup instructions as follows: +* Install PyUSB (pip install --pre pysusb) +* Plug in the STLink or another power source to power the ODrive board +* Plug in a separate USB cable into the microUSB connector on ODrive +* On Windows, use the [Zadig](http://zadig.akeo.ie/) utility to set ODrive (not STLink!) driver to libusb +* Run test_bulk.py ### Command set The most accurate way to understand the commands is to read [the code](https://github.com/madcowswe/ODriveFirmware/blob/f19f1b78de4bd917284ff95bc61ca616ca9bacc4/MotorControl/low_level.c#L353) that parses the commands. From d6646b5a94ee8b6c2b02a6229f176b0e984c79ee Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Fri, 22 Sep 2017 22:37:16 -0700 Subject: [PATCH 09/35] Fix newest Cube code was v3.2, now correctly v3.3 --- Inc/main.h | 32 ++++++++++---------- Inc/stm32f4xx_it.h | 2 +- Odrive.ioc | 75 +++++++++++++++++++++++----------------------- Src/adc.c | 34 ++++++++++----------- Src/gpio.c | 42 ++++++++++---------------- Src/stm32f4xx_it.c | 28 ++++++++--------- 6 files changed, 99 insertions(+), 114 deletions(-) diff --git a/Inc/main.h b/Inc/main.h index dfaf2685..a2fdb772 100644 --- a/Inc/main.h +++ b/Inc/main.h @@ -79,21 +79,22 @@ #define M1_IC_GPIO_Port GPIOC #define M1_IB_Pin GPIO_PIN_3 #define M1_IB_GPIO_Port GPIOC -#define VBUS_S_Pin GPIO_PIN_0 -#define VBUS_S_GPIO_Port GPIOA -#define M1_TEMP_Pin GPIO_PIN_1 -#define M1_TEMP_GPIO_Port GPIOA -#define AUX_I_Pin GPIO_PIN_2 -#define AUX_I_GPIO_Port GPIOA +#define GPIO_1_Pin GPIO_PIN_0 +#define GPIO_1_GPIO_Port GPIOA +#define GPIO_1_EXTI_IRQn EXTI0_IRQn +#define GPIO_2_Pin GPIO_PIN_1 +#define GPIO_2_GPIO_Port GPIOA +#define GPIO_3_Pin GPIO_PIN_2 +#define GPIO_3_GPIO_Port GPIOA +#define GPIO_3_EXTI_IRQn EXTI2_IRQn #define GPIO_4_Pin GPIO_PIN_3 #define GPIO_4_GPIO_Port GPIOA -#define GPIO_3_Pin GPIO_PIN_4 -#define GPIO_3_GPIO_Port GPIOA -#define GPIO_3_EXTI_IRQn EXTI4_IRQn -#define GPIO_2_Pin GPIO_PIN_5 -#define GPIO_2_GPIO_Port GPIOA -#define AUX_V_Pin GPIO_PIN_6 -#define AUX_V_GPIO_Port GPIOA +#define M1_TEMP_Pin GPIO_PIN_4 +#define M1_TEMP_GPIO_Port GPIOA +#define AUX_I_Pin GPIO_PIN_5 +#define AUX_I_GPIO_Port GPIOA +#define VBUS_S_Pin GPIO_PIN_6 +#define VBUS_S_GPIO_Port GPIOA #define M1_AL_Pin GPIO_PIN_7 #define M1_AL_GPIO_Port GPIOA #define AUX_TEMP_Pin GPIO_PIN_4 @@ -104,9 +105,8 @@ #define M1_BL_GPIO_Port GPIOB #define M1_CL_Pin GPIO_PIN_1 #define M1_CL_GPIO_Port GPIOB -#define GPIO_1_Pin GPIO_PIN_2 -#define GPIO_1_GPIO_Port GPIOB -#define GPIO_1_EXTI_IRQn EXTI2_IRQn +#define GPIO_5_Pin GPIO_PIN_2 +#define GPIO_5_GPIO_Port GPIOB #define AUX_L_Pin GPIO_PIN_10 #define AUX_L_GPIO_Port GPIOB #define AUX_H_Pin GPIO_PIN_11 diff --git a/Inc/stm32f4xx_it.h b/Inc/stm32f4xx_it.h index caaf7ef3..74b19b28 100644 --- a/Inc/stm32f4xx_it.h +++ b/Inc/stm32f4xx_it.h @@ -52,8 +52,8 @@ void BusFault_Handler(void); void UsageFault_Handler(void); void DebugMon_Handler(void); void SysTick_Handler(void); +void EXTI0_IRQHandler(void); void EXTI2_IRQHandler(void); -void EXTI4_IRQHandler(void); void ADC_IRQHandler(void); void OTG_FS_IRQHandler(void); diff --git a/Odrive.ioc b/Odrive.ioc index d99a7c69..b7bd70f6 100755 --- a/Odrive.ioc +++ b/Odrive.ioc @@ -1,6 +1,6 @@ #MicroXplorer Configuration settings - do not modify -ADC1.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_0 -ADC1.Channel-1\#ChannelInjectedConversion=ADC_CHANNEL_0 +ADC1.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_6 +ADC1.Channel-1\#ChannelInjectedConversion=ADC_CHANNEL_6 ADC1.ClockPrescaler=ADC_CLOCK_SYNC_PCLK_DIV4 ADC1.ContinuousConvMode=DISABLE ADC1.DMAContinuousRequests=DISABLE @@ -169,8 +169,8 @@ MxDb.Version=DB.4.0.220 NVIC.ADC_IRQn=true\:5\:0\:false\:false\:true\:true NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false +NVIC.EXTI0_IRQn=true\:0\:0\:false\:false\:true\:false NVIC.EXTI2_IRQn=true\:0\:0\:false\:false\:true\:false -NVIC.EXTI4_IRQn=true\:0\:0\:false\:false\:true\:false NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false @@ -180,12 +180,16 @@ NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:false\:false NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:true NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false -PA0-WKUP.GPIOParameters=GPIO_Label -PA0-WKUP.GPIO_Label=VBUS_S -PA0-WKUP.Signal=ADCx_IN0 -PA1.GPIOParameters=GPIO_Label -PA1.GPIO_Label=M1_TEMP -PA1.Signal=ADCx_IN1 +PA0-WKUP.GPIOParameters=GPIO_PuPd,GPIO_Label +PA0-WKUP.GPIO_Label=GPIO_1 +PA0-WKUP.GPIO_PuPd=GPIO_PULLDOWN +PA0-WKUP.Locked=true +PA0-WKUP.Signal=GPXTI0 +PA1.GPIOParameters=GPIO_PuPd,GPIO_Label +PA1.GPIO_Label=GPIO_2 +PA1.GPIO_PuPd=GPIO_NOPULL +PA1.Locked=true +PA1.Signal=GPIO_Input PA10.GPIOParameters=GPIO_Label PA10.GPIO_Label=M0_CH PA10.Locked=true @@ -202,26 +206,27 @@ PA15.GPIOParameters=GPIO_Label PA15.GPIO_Label=M0_ENC_Z PA15.Locked=true PA15.Signal=GPIO_Input -PA2.GPIOParameters=GPIO_Label -PA2.GPIO_Label=AUX_I -PA2.Signal=ADCx_IN2 +PA2.GPIOParameters=GPIO_PuPd,GPIO_Label +PA2.GPIO_Label=GPIO_3 +PA2.GPIO_PuPd=GPIO_PULLDOWN +PA2.Locked=true +PA2.Signal=GPXTI2 PA3.GPIOParameters=GPIO_PuPd,GPIO_Label PA3.GPIO_Label=GPIO_4 -PA3.GPIO_PuPd=GPIO_PULLDOWN +PA3.GPIO_PuPd=GPIO_NOPULL PA3.Locked=true PA3.Signal=GPIO_Input -PA4.GPIOParameters=GPIO_PuPd,GPIO_Label -PA4.GPIO_Label=GPIO_3 -PA4.GPIO_PuPd=GPIO_PULLDOWN +PA4.GPIOParameters=GPIO_Label +PA4.GPIO_Label=M1_TEMP PA4.Locked=true -PA4.Signal=GPXTI4 -PA5.GPIOParameters=GPIO_PuPd,GPIO_Label -PA5.GPIO_Label=GPIO_2 -PA5.GPIO_PuPd=GPIO_PULLDOWN +PA4.Signal=ADCx_IN4 +PA5.GPIOParameters=GPIO_Label +PA5.GPIO_Label=AUX_I PA5.Locked=true -PA5.Signal=GPIO_Input +PA5.Signal=ADCx_IN5 PA6.GPIOParameters=GPIO_Label -PA6.GPIO_Label=AUX_V +PA6.GPIO_Label=VBUS_S +PA6.Locked=true PA6.Signal=ADCx_IN6 PA7.GPIOParameters=GPIO_Label PA7.GPIO_Label=M1_AL @@ -273,11 +278,10 @@ PB15.GPIO_Label=M0_CL PB15.Locked=true PB15.Mode=PWM Generation3 CH3 CH3N PB15.Signal=TIM1_CH3N -PB2.GPIOParameters=GPIO_PuPd,GPIO_Label -PB2.GPIO_Label=GPIO_1 -PB2.GPIO_PuPd=GPIO_PULLDOWN +PB2.GPIOParameters=GPIO_Label +PB2.GPIO_Label=GPIO_5 PB2.Locked=true -PB2.Signal=GPXTI2 +PB2.Signal=GPIO_Input PB3.GPIOParameters=GPIO_Label PB3.GPIO_Label=M1_ENC_Z PB3.Locked=true @@ -429,12 +433,6 @@ RCC.VCOI2SOutputFreq_Value=384000000 RCC.VCOInputFreq_Value=2000000 RCC.VCOOutputFreq_Value=336000000 RCC.VcooutputI2S=192000000 -SH.ADCx_IN0.0=ADC1_IN0,IN0 -SH.ADCx_IN0.1=ADC2_IN0,IN0 -SH.ADCx_IN0.ConfNb=2 -SH.ADCx_IN1.0=ADC1_IN1,IN1 -SH.ADCx_IN1.1=ADC2_IN1,IN1 -SH.ADCx_IN1.ConfNb=2 SH.ADCx_IN10.0=ADC1_IN10,IN10 SH.ADCx_IN10.1=ADC2_IN10,IN10 SH.ADCx_IN10.2=ADC3_IN10,IN10 @@ -457,16 +455,19 @@ SH.ADCx_IN14.ConfNb=2 SH.ADCx_IN15.0=ADC1_IN15,IN15 SH.ADCx_IN15.1=ADC2_IN15,IN15 SH.ADCx_IN15.ConfNb=2 -SH.ADCx_IN2.0=ADC1_IN2,IN2 -SH.ADCx_IN2.1=ADC2_IN2,IN2 -SH.ADCx_IN2.ConfNb=2 +SH.ADCx_IN4.0=ADC1_IN4,IN4 +SH.ADCx_IN4.1=ADC2_IN4,IN4 +SH.ADCx_IN4.ConfNb=2 +SH.ADCx_IN5.0=ADC1_IN5,IN5 +SH.ADCx_IN5.1=ADC2_IN5,IN5 +SH.ADCx_IN5.ConfNb=2 SH.ADCx_IN6.0=ADC1_IN6,IN6 SH.ADCx_IN6.1=ADC2_IN6,IN6 SH.ADCx_IN6.ConfNb=2 +SH.GPXTI0.0=GPIO_EXTI0 +SH.GPXTI0.ConfNb=1 SH.GPXTI2.0=GPIO_EXTI2 SH.GPXTI2.ConfNb=1 -SH.GPXTI4.0=GPIO_EXTI4 -SH.GPXTI4.ConfNb=1 SH.S_TIM1_CH1.0=TIM1_CH1,PWM Generation1 CH1 CH1N SH.S_TIM1_CH1.ConfNb=1 SH.S_TIM1_CH2.0=TIM1_CH2,PWM Generation2 CH2 CH2N diff --git a/Src/adc.c b/Src/adc.c index 7f4fb173..6069ef4c 100644 --- a/Src/adc.c +++ b/Src/adc.c @@ -49,6 +49,7 @@ /* Includes ------------------------------------------------------------------*/ #include "adc.h" + #include "gpio.h" /* USER CODE BEGIN 0 */ @@ -59,7 +60,6 @@ #else /* USER CODE END 0 */ - ADC_HandleTypeDef hadc1; ADC_HandleTypeDef hadc2; ADC_HandleTypeDef hadc3; @@ -91,7 +91,7 @@ void MX_ADC1_Init(void) /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. */ - sConfig.Channel = ADC_CHANNEL_0; + sConfig.Channel = ADC_CHANNEL_6; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) @@ -101,7 +101,7 @@ void MX_ADC1_Init(void) /**Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time */ - sConfigInjected.InjectedChannel = ADC_CHANNEL_0; + sConfigInjected.InjectedChannel = ADC_CHANNEL_6; sConfigInjected.InjectedRank = 1; sConfigInjected.InjectedNbrOfConversion = 1; sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_3CYCLES; @@ -238,9 +238,8 @@ void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle) PC1 ------> ADC1_IN11 PC2 ------> ADC1_IN12 PC3 ------> ADC1_IN13 - PA0-WKUP ------> ADC1_IN0 - PA1 ------> ADC1_IN1 - PA2 ------> ADC1_IN2 + PA4 ------> ADC1_IN4 + PA5 ------> ADC1_IN5 PA6 ------> ADC1_IN6 PC4 ------> ADC1_IN14 PC5 ------> ADC1_IN15 @@ -251,7 +250,7 @@ void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle) GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); - GPIO_InitStruct.Pin = VBUS_S_Pin|M1_TEMP_Pin|AUX_I_Pin|AUX_V_Pin; + GPIO_InitStruct.Pin = M1_TEMP_Pin|AUX_I_Pin|VBUS_S_Pin; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); @@ -276,9 +275,8 @@ void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle) PC1 ------> ADC2_IN11 PC2 ------> ADC2_IN12 PC3 ------> ADC2_IN13 - PA0-WKUP ------> ADC2_IN0 - PA1 ------> ADC2_IN1 - PA2 ------> ADC2_IN2 + PA4 ------> ADC2_IN4 + PA5 ------> ADC2_IN5 PA6 ------> ADC2_IN6 PC4 ------> ADC2_IN14 PC5 ------> ADC2_IN15 @@ -289,7 +287,7 @@ void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle) GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); - GPIO_InitStruct.Pin = VBUS_S_Pin|M1_TEMP_Pin|AUX_I_Pin|AUX_V_Pin; + GPIO_InitStruct.Pin = M1_TEMP_Pin|AUX_I_Pin|VBUS_S_Pin; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); @@ -345,9 +343,8 @@ void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle) PC1 ------> ADC1_IN11 PC2 ------> ADC1_IN12 PC3 ------> ADC1_IN13 - PA0-WKUP ------> ADC1_IN0 - PA1 ------> ADC1_IN1 - PA2 ------> ADC1_IN2 + PA4 ------> ADC1_IN4 + PA5 ------> ADC1_IN5 PA6 ------> ADC1_IN6 PC4 ------> ADC1_IN14 PC5 ------> ADC1_IN15 @@ -355,7 +352,7 @@ void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle) HAL_GPIO_DeInit(GPIOC, M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin |AUX_TEMP_Pin|M0_TEMP_Pin); - HAL_GPIO_DeInit(GPIOA, VBUS_S_Pin|M1_TEMP_Pin|AUX_I_Pin|AUX_V_Pin); + HAL_GPIO_DeInit(GPIOA, M1_TEMP_Pin|AUX_I_Pin|VBUS_S_Pin); /* ADC1 interrupt Deinit */ /* USER CODE BEGIN ADC1:ADC_IRQn disable */ @@ -383,9 +380,8 @@ void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle) PC1 ------> ADC2_IN11 PC2 ------> ADC2_IN12 PC3 ------> ADC2_IN13 - PA0-WKUP ------> ADC2_IN0 - PA1 ------> ADC2_IN1 - PA2 ------> ADC2_IN2 + PA4 ------> ADC2_IN4 + PA5 ------> ADC2_IN5 PA6 ------> ADC2_IN6 PC4 ------> ADC2_IN14 PC5 ------> ADC2_IN15 @@ -393,7 +389,7 @@ void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle) HAL_GPIO_DeInit(GPIOC, M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin |AUX_TEMP_Pin|M0_TEMP_Pin); - HAL_GPIO_DeInit(GPIOA, VBUS_S_Pin|M1_TEMP_Pin|AUX_I_Pin|AUX_V_Pin); + HAL_GPIO_DeInit(GPIOA, M1_TEMP_Pin|AUX_I_Pin|VBUS_S_Pin); /* ADC2 interrupt Deinit */ /* USER CODE BEGIN ADC2:ADC_IRQn disable */ diff --git a/Src/gpio.c b/Src/gpio.c index 9dfb3836..a7752882 100644 --- a/Src/gpio.c +++ b/Src/gpio.c @@ -101,22 +101,22 @@ void MX_GPIO_Init(void) HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); /*Configure GPIO pins : PAPin PAPin */ - GPIO_InitStruct.Pin = GPIO_4_Pin|GPIO_2_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pin = GPIO_1_Pin|GPIO_3_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; GPIO_InitStruct.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - /*Configure GPIO pin : PtPin */ - GPIO_InitStruct.Pin = GPIO_3_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; - GPIO_InitStruct.Pull = GPIO_PULLDOWN; - HAL_GPIO_Init(GPIO_3_GPIO_Port, &GPIO_InitStruct); + /*Configure GPIO pins : PAPin PAPin PAPin */ + GPIO_InitStruct.Pin = GPIO_2_Pin|GPIO_4_Pin|M0_ENC_Z_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - /*Configure GPIO pin : PtPin */ - GPIO_InitStruct.Pin = GPIO_1_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; - GPIO_InitStruct.Pull = GPIO_PULLDOWN; - HAL_GPIO_Init(GPIO_1_GPIO_Port, &GPIO_InitStruct); + /*Configure GPIO pins : PBPin PBPin */ + GPIO_InitStruct.Pin = GPIO_5_Pin|M1_ENC_Z_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /*Configure GPIO pin : PtPin */ GPIO_InitStruct.Pin = EN_GATE_Pin; @@ -125,31 +125,19 @@ void MX_GPIO_Init(void) GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(EN_GATE_GPIO_Port, &GPIO_InitStruct); - /*Configure GPIO pin : PtPin */ - GPIO_InitStruct.Pin = M0_ENC_Z_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_INPUT; - GPIO_InitStruct.Pull = GPIO_NOPULL; - HAL_GPIO_Init(M0_ENC_Z_GPIO_Port, &GPIO_InitStruct); - /*Configure GPIO pin : PtPin */ GPIO_InitStruct.Pin = nFAULT_Pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(nFAULT_GPIO_Port, &GPIO_InitStruct); - /*Configure GPIO pin : PtPin */ - GPIO_InitStruct.Pin = M1_ENC_Z_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_INPUT; - GPIO_InitStruct.Pull = GPIO_NOPULL; - HAL_GPIO_Init(M1_ENC_Z_GPIO_Port, &GPIO_InitStruct); - /* EXTI interrupt init*/ + HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(EXTI0_IRQn); + HAL_NVIC_SetPriority(EXTI2_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI2_IRQn); - HAL_NVIC_SetPriority(EXTI4_IRQn, 0, 0); - HAL_NVIC_EnableIRQ(EXTI4_IRQn); - } /* USER CODE BEGIN 2 */ diff --git a/Src/stm32f4xx_it.c b/Src/stm32f4xx_it.c index c9bf4b4b..8b218e23 100644 --- a/Src/stm32f4xx_it.c +++ b/Src/stm32f4xx_it.c @@ -171,6 +171,20 @@ void SysTick_Handler(void) /* please refer to the startup file (startup_stm32f4xx.s). */ /******************************************************************************/ +/** +* @brief This function handles EXTI line0 interrupt. +*/ +void EXTI0_IRQHandler(void) +{ + /* USER CODE BEGIN EXTI0_IRQn 0 */ + + /* USER CODE END EXTI0_IRQn 0 */ + HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); + /* USER CODE BEGIN EXTI0_IRQn 1 */ + + /* USER CODE END EXTI0_IRQn 1 */ +} + /** * @brief This function handles EXTI line2 interrupt. */ @@ -185,20 +199,6 @@ void EXTI2_IRQHandler(void) /* USER CODE END EXTI2_IRQn 1 */ } -/** -* @brief This function handles EXTI line4 interrupt. -*/ -void EXTI4_IRQHandler(void) -{ - /* USER CODE BEGIN EXTI4_IRQn 0 */ - - /* USER CODE END EXTI4_IRQn 0 */ - HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4); - /* USER CODE BEGIN EXTI4_IRQn 1 */ - - /* USER CODE END EXTI4_IRQn 1 */ -} - /** * @brief This function handles ADC1, ADC2 and ADC3 global interrupts. */ From 61860ff38e4a1edf966289febe2a5b1cceab358f Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sat, 23 Sep 2017 01:49:31 -0700 Subject: [PATCH 10/35] Bring up UART4 --- .../Inc/stm32f4xx_hal_uart.h | 794 ++++++ .../Src/stm32f4xx_hal_uart.c | 2539 +++++++++++++++++ Inc/gpio.h | 3 + Inc/main.h | 1 - Inc/stm32f4xx_hal_conf.h | 2 +- Inc/stm32f4xx_it.h | 2 - Inc/usart.h | 91 + Makefile | 2 + Odrive.ioc | 28 +- Src/gpio.c | 68 +- Src/main.c | 2 + Src/stm32f4xx_it.c | 45 +- Src/usart.c | 151 + 13 files changed, 3678 insertions(+), 50 deletions(-) create mode 100644 Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_uart.h create mode 100644 Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c create mode 100644 Inc/usart.h create mode 100644 Src/usart.c diff --git a/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_uart.h b/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_uart.h new file mode 100644 index 00000000..ba2ed4f8 --- /dev/null +++ b/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_uart.h @@ -0,0 +1,794 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_uart.h + * @author MCD Application Team + * @version V1.7.1 + * @date 14-April-2017 + * @brief Header file of UART HAL module. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_UART_H +#define __STM32F4xx_HAL_UART_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal_def.h" + +/** @addtogroup STM32F4xx_HAL_Driver + * @{ + */ + +/** @addtogroup UART + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +/** @defgroup UART_Exported_Types UART Exported Types + * @{ + */ + +/** + * @brief UART Init Structure definition + */ +typedef struct +{ + uint32_t BaudRate; /*!< This member configures the UART communication baud rate. + The baud rate is computed using the following formula: + - IntegerDivider = ((PCLKx) / (8 * (OVR8+1) * (huart->Init.BaudRate))) + - FractionalDivider = ((IntegerDivider - ((uint32_t) IntegerDivider)) * 8 * (OVR8+1)) + 0.5 + Where OVR8 is the "oversampling by 8 mode" configuration bit in the CR1 register. */ + + uint32_t WordLength; /*!< Specifies the number of data bits transmitted or received in a frame. + This parameter can be a value of @ref UART_Word_Length */ + + uint32_t StopBits; /*!< Specifies the number of stop bits transmitted. + This parameter can be a value of @ref UART_Stop_Bits */ + + uint32_t Parity; /*!< Specifies the parity mode. + This parameter can be a value of @ref UART_Parity + @note When parity is enabled, the computed parity is inserted + at the MSB position of the transmitted data (9th bit when + the word length is set to 9 data bits; 8th bit when the + word length is set to 8 data bits). */ + + uint32_t Mode; /*!< Specifies whether the Receive or Transmit mode is enabled or disabled. + This parameter can be a value of @ref UART_Mode */ + + uint32_t HwFlowCtl; /*!< Specifies whether the hardware flow control mode is enabled + or disabled. + This parameter can be a value of @ref UART_Hardware_Flow_Control */ + + uint32_t OverSampling; /*!< Specifies whether the Over sampling 8 is enabled or disabled, to achieve higher speed (up to fPCLK/8). + This parameter can be a value of @ref UART_Over_Sampling */ +}UART_InitTypeDef; + +/** + * @brief HAL UART State structures definition + * @note HAL UART State value is a combination of 2 different substates: gState and RxState. + * - gState contains UART state information related to global Handle management + * and also information related to Tx operations. + * gState value coding follow below described bitmap : + * b7-b6 Error information + * 00 : No Error + * 01 : (Not Used) + * 10 : Timeout + * 11 : Error + * b5 IP initilisation status + * 0 : Reset (IP not initialized) + * 1 : Init done (IP not initialized. HAL UART Init function already called) + * b4-b3 (not used) + * xx : Should be set to 00 + * b2 Intrinsic process state + * 0 : Ready + * 1 : Busy (IP busy with some configuration or internal operations) + * b1 (not used) + * x : Should be set to 0 + * b0 Tx state + * 0 : Ready (no Tx operation ongoing) + * 1 : Busy (Tx operation ongoing) + * - RxState contains information related to Rx operations. + * RxState value coding follow below described bitmap : + * b7-b6 (not used) + * xx : Should be set to 00 + * b5 IP initilisation status + * 0 : Reset (IP not initialized) + * 1 : Init done (IP not initialized) + * b4-b2 (not used) + * xxx : Should be set to 000 + * b1 Rx state + * 0 : Ready (no Rx operation ongoing) + * 1 : Busy (Rx operation ongoing) + * b0 (not used) + * x : Should be set to 0. + */ +typedef enum +{ + HAL_UART_STATE_RESET = 0x00U, /*!< Peripheral is not yet Initialized + Value is allowed for gState and RxState */ + HAL_UART_STATE_READY = 0x20U, /*!< Peripheral Initialized and ready for use + Value is allowed for gState and RxState */ + HAL_UART_STATE_BUSY = 0x24U, /*!< an internal process is ongoing + Value is allowed for gState only */ + HAL_UART_STATE_BUSY_TX = 0x21U, /*!< Data Transmission process is ongoing + Value is allowed for gState only */ + HAL_UART_STATE_BUSY_RX = 0x22U, /*!< Data Reception process is ongoing + Value is allowed for RxState only */ + HAL_UART_STATE_BUSY_TX_RX = 0x23U, /*!< Data Transmission and Reception process is ongoing + Not to be used for neither gState nor RxState. + Value is result of combination (Or) between gState and RxState values */ + HAL_UART_STATE_TIMEOUT = 0xA0U, /*!< Timeout state + Value is allowed for gState only */ + HAL_UART_STATE_ERROR = 0xE0U /*!< Error + Value is allowed for gState only */ +}HAL_UART_StateTypeDef; + +/** + * @brief UART handle Structure definition + */ +typedef struct +{ + USART_TypeDef *Instance; /*!< UART registers base address */ + + UART_InitTypeDef Init; /*!< UART communication parameters */ + + uint8_t *pTxBuffPtr; /*!< Pointer to UART Tx transfer Buffer */ + + uint16_t TxXferSize; /*!< UART Tx Transfer size */ + + __IO uint16_t TxXferCount; /*!< UART Tx Transfer Counter */ + + uint8_t *pRxBuffPtr; /*!< Pointer to UART Rx transfer Buffer */ + + uint16_t RxXferSize; /*!< UART Rx Transfer size */ + + __IO uint16_t RxXferCount; /*!< UART Rx Transfer Counter */ + + DMA_HandleTypeDef *hdmatx; /*!< UART Tx DMA Handle parameters */ + + DMA_HandleTypeDef *hdmarx; /*!< UART Rx DMA Handle parameters */ + + HAL_LockTypeDef Lock; /*!< Locking object */ + + __IO HAL_UART_StateTypeDef gState; /*!< UART state information related to global Handle management + and also related to Tx operations. + This parameter can be a value of @ref HAL_UART_StateTypeDef */ + + __IO HAL_UART_StateTypeDef RxState; /*!< UART state information related to Rx operations. + This parameter can be a value of @ref HAL_UART_StateTypeDef */ + + __IO uint32_t ErrorCode; /*!< UART Error code */ + +}UART_HandleTypeDef; +/** + * @} + */ + +/* Exported constants --------------------------------------------------------*/ +/** @defgroup UART_Exported_Constants UART Exported constants + * @{ + */ + +/** @defgroup UART_Error_Code UART Error Code + * @brief UART Error Code + * @{ + */ +#define HAL_UART_ERROR_NONE 0x00000000U /*!< No error */ +#define HAL_UART_ERROR_PE 0x00000001U /*!< Parity error */ +#define HAL_UART_ERROR_NE 0x00000002U /*!< Noise error */ +#define HAL_UART_ERROR_FE 0x00000004U /*!< Frame error */ +#define HAL_UART_ERROR_ORE 0x00000008U /*!< Overrun error */ +#define HAL_UART_ERROR_DMA 0x00000010U /*!< DMA transfer error */ +/** + * @} + */ + +/** @defgroup UART_Word_Length UART Word Length + * @{ + */ +#define UART_WORDLENGTH_8B 0x00000000U +#define UART_WORDLENGTH_9B ((uint32_t)USART_CR1_M) +/** + * @} + */ + +/** @defgroup UART_Stop_Bits UART Number of Stop Bits + * @{ + */ +#define UART_STOPBITS_1 0x00000000U +#define UART_STOPBITS_2 ((uint32_t)USART_CR2_STOP_1) +/** + * @} + */ + +/** @defgroup UART_Parity UART Parity + * @{ + */ +#define UART_PARITY_NONE 0x00000000U +#define UART_PARITY_EVEN ((uint32_t)USART_CR1_PCE) +#define UART_PARITY_ODD ((uint32_t)(USART_CR1_PCE | USART_CR1_PS)) +/** + * @} + */ + +/** @defgroup UART_Hardware_Flow_Control UART Hardware Flow Control + * @{ + */ +#define UART_HWCONTROL_NONE 0x00000000U +#define UART_HWCONTROL_RTS ((uint32_t)USART_CR3_RTSE) +#define UART_HWCONTROL_CTS ((uint32_t)USART_CR3_CTSE) +#define UART_HWCONTROL_RTS_CTS ((uint32_t)(USART_CR3_RTSE | USART_CR3_CTSE)) +/** + * @} + */ + +/** @defgroup UART_Mode UART Transfer Mode + * @{ + */ +#define UART_MODE_RX ((uint32_t)USART_CR1_RE) +#define UART_MODE_TX ((uint32_t)USART_CR1_TE) +#define UART_MODE_TX_RX ((uint32_t)(USART_CR1_TE |USART_CR1_RE)) +/** + * @} + */ + + /** @defgroup UART_State UART State + * @{ + */ +#define UART_STATE_DISABLE 0x00000000U +#define UART_STATE_ENABLE ((uint32_t)USART_CR1_UE) +/** + * @} + */ + +/** @defgroup UART_Over_Sampling UART Over Sampling + * @{ + */ +#define UART_OVERSAMPLING_16 0x00000000U +#define UART_OVERSAMPLING_8 ((uint32_t)USART_CR1_OVER8) +/** + * @} + */ + +/** @defgroup UART_LIN_Break_Detection_Length UART LIN Break Detection Length + * @{ + */ +#define UART_LINBREAKDETECTLENGTH_10B 0x00000000U +#define UART_LINBREAKDETECTLENGTH_11B 0x00000020U +/** + * @} + */ + +/** @defgroup UART_WakeUp_functions UART Wakeup Functions + * @{ + */ +#define UART_WAKEUPMETHOD_IDLELINE 0x00000000U +#define UART_WAKEUPMETHOD_ADDRESSMARK 0x00000800U +/** + * @} + */ + +/** @defgroup UART_Flags UART FLags + * Elements values convention: 0xXXXX + * - 0xXXXX : Flag mask in the SR register + * @{ + */ +#define UART_FLAG_CTS ((uint32_t)USART_SR_CTS) +#define UART_FLAG_LBD ((uint32_t)USART_SR_LBD) +#define UART_FLAG_TXE ((uint32_t)USART_SR_TXE) +#define UART_FLAG_TC ((uint32_t)USART_SR_TC) +#define UART_FLAG_RXNE ((uint32_t)USART_SR_RXNE) +#define UART_FLAG_IDLE ((uint32_t)USART_SR_IDLE) +#define UART_FLAG_ORE ((uint32_t)USART_SR_ORE) +#define UART_FLAG_NE ((uint32_t)USART_SR_NE) +#define UART_FLAG_FE ((uint32_t)USART_SR_FE) +#define UART_FLAG_PE ((uint32_t)USART_SR_PE) +/** + * @} + */ + +/** @defgroup UART_Interrupt_definition UART Interrupt Definitions + * Elements values convention: 0xY000XXXX + * - XXXX : Interrupt mask (16 bits) in the Y register + * - Y : Interrupt source register (2bits) + * - 0001: CR1 register + * - 0010: CR2 register + * - 0011: CR3 register + * + * @{ + */ + +#define UART_IT_PE ((uint32_t)(UART_CR1_REG_INDEX << 28U | USART_CR1_PEIE)) +#define UART_IT_TXE ((uint32_t)(UART_CR1_REG_INDEX << 28U | USART_CR1_TXEIE)) +#define UART_IT_TC ((uint32_t)(UART_CR1_REG_INDEX << 28U | USART_CR1_TCIE)) +#define UART_IT_RXNE ((uint32_t)(UART_CR1_REG_INDEX << 28U | USART_CR1_RXNEIE)) +#define UART_IT_IDLE ((uint32_t)(UART_CR1_REG_INDEX << 28U | USART_CR1_IDLEIE)) + +#define UART_IT_LBD ((uint32_t)(UART_CR2_REG_INDEX << 28U | USART_CR2_LBDIE)) + +#define UART_IT_CTS ((uint32_t)(UART_CR3_REG_INDEX << 28U | USART_CR3_CTSIE)) +#define UART_IT_ERR ((uint32_t)(UART_CR3_REG_INDEX << 28U | USART_CR3_EIE)) +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/** @defgroup UART_Exported_Macros UART Exported Macros + * @{ + */ + +/** @brief Reset UART handle gstate & RxState + * @param __HANDLE__: specifies the UART Handle. + * This parameter can be UARTx where x: 1, 2, 3, 4, 5, 6, 7 or 8 to select the USART or + * UART peripheral. + * @retval None + */ +#define __HAL_UART_RESET_HANDLE_STATE(__HANDLE__) do{ \ + (__HANDLE__)->gState = HAL_UART_STATE_RESET; \ + (__HANDLE__)->RxState = HAL_UART_STATE_RESET; \ + } while(0U) + +/** @brief Flushes the UART DR register + * @param __HANDLE__: specifies the UART Handle. + */ +#define __HAL_UART_FLUSH_DRREGISTER(__HANDLE__) ((__HANDLE__)->Instance->DR) + +/** @brief Checks whether the specified UART flag is set or not. + * @param __HANDLE__: specifies the UART Handle. + * This parameter can be UARTx where x: 1, 2, 3, 4, 5, 6, 7 or 8 to select the USART or + * UART peripheral. + * @param __FLAG__: specifies the flag to check. + * This parameter can be one of the following values: + * @arg UART_FLAG_CTS: CTS Change flag (not available for UART4 and UART5) + * @arg UART_FLAG_LBD: LIN Break detection flag + * @arg UART_FLAG_TXE: Transmit data register empty flag + * @arg UART_FLAG_TC: Transmission Complete flag + * @arg UART_FLAG_RXNE: Receive data register not empty flag + * @arg UART_FLAG_IDLE: Idle Line detection flag + * @arg UART_FLAG_ORE: Overrun Error flag + * @arg UART_FLAG_NE: Noise Error flag + * @arg UART_FLAG_FE: Framing Error flag + * @arg UART_FLAG_PE: Parity Error flag + * @retval The new state of __FLAG__ (TRUE or FALSE). + */ + +#define __HAL_UART_GET_FLAG(__HANDLE__, __FLAG__) (((__HANDLE__)->Instance->SR & (__FLAG__)) == (__FLAG__)) + +/** @brief Clears the specified UART pending flag. + * @param __HANDLE__: specifies the UART Handle. + * This parameter can be UARTx where x: 1, 2, 3, 4, 5, 6, 7 or 8 to select the USART or + * UART peripheral. + * @param __FLAG__: specifies the flag to check. + * This parameter can be any combination of the following values: + * @arg UART_FLAG_CTS: CTS Change flag (not available for UART4 and UART5). + * @arg UART_FLAG_LBD: LIN Break detection flag. + * @arg UART_FLAG_TC: Transmission Complete flag. + * @arg UART_FLAG_RXNE: Receive data register not empty flag. + * + * @note PE (Parity error), FE (Framing error), NE (Noise error), ORE (Overrun + * error) and IDLE (Idle line detected) flags are cleared by software + * sequence: a read operation to USART_SR register followed by a read + * operation to USART_DR register. + * @note RXNE flag can be also cleared by a read to the USART_DR register. + * @note TC flag can be also cleared by software sequence: a read operation to + * USART_SR register followed by a write operation to USART_DR register. + * @note TXE flag is cleared only by a write to the USART_DR register. + * + * @retval None + */ +#define __HAL_UART_CLEAR_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->Instance->SR = ~(__FLAG__)) + +/** @brief Clear the UART PE pending flag. + * @param __HANDLE__: specifies the UART Handle. + * This parameter can be UARTx where x: 1, 2, 3, 4, 5, 6, 7 or 8 to select the USART or + * UART peripheral. + * @retval None + */ +#define __HAL_UART_CLEAR_PEFLAG(__HANDLE__) \ + do{ \ + __IO uint32_t tmpreg = 0x00U; \ + tmpreg = (__HANDLE__)->Instance->SR; \ + tmpreg = (__HANDLE__)->Instance->DR; \ + UNUSED(tmpreg); \ + } while(0U) + +/** @brief Clear the UART FE pending flag. + * @param __HANDLE__: specifies the UART Handle. + * This parameter can be UARTx where x: 1, 2, 3, 4, 5, 6, 7 or 8 to select the USART or + * UART peripheral. + * @retval None + */ +#define __HAL_UART_CLEAR_FEFLAG(__HANDLE__) __HAL_UART_CLEAR_PEFLAG(__HANDLE__) + +/** @brief Clear the UART NE pending flag. + * @param __HANDLE__: specifies the UART Handle. + * This parameter can be UARTx where x: 1, 2, 3, 4, 5, 6, 7 or 8 to select the USART or + * UART peripheral. + * @retval None + */ +#define __HAL_UART_CLEAR_NEFLAG(__HANDLE__) __HAL_UART_CLEAR_PEFLAG(__HANDLE__) + +/** @brief Clear the UART ORE pending flag. + * @param __HANDLE__: specifies the UART Handle. + * This parameter can be UARTx where x: 1, 2, 3, 4, 5, 6, 7 or 8 to select the USART or + * UART peripheral. + * @retval None + */ +#define __HAL_UART_CLEAR_OREFLAG(__HANDLE__) __HAL_UART_CLEAR_PEFLAG(__HANDLE__) + +/** @brief Clear the UART IDLE pending flag. + * @param __HANDLE__: specifies the UART Handle. + * This parameter can be UARTx where x: 1, 2, 3, 4, 5, 6, 7 or 8 to select the USART or + * UART peripheral. + * @retval None + */ +#define __HAL_UART_CLEAR_IDLEFLAG(__HANDLE__) __HAL_UART_CLEAR_PEFLAG(__HANDLE__) + +/** @brief Enable the specified UART interrupt. + * @param __HANDLE__: specifies the UART Handle. + * This parameter can be UARTx where x: 1, 2, 3, 4, 5, 6, 7 or 8 to select the USART or + * UART peripheral. + * @param __INTERRUPT__: specifies the UART interrupt source to enable. + * This parameter can be one of the following values: + * @arg UART_IT_CTS: CTS change interrupt + * @arg UART_IT_LBD: LIN Break detection interrupt + * @arg UART_IT_TXE: Transmit Data Register empty interrupt + * @arg UART_IT_TC: Transmission complete interrupt + * @arg UART_IT_RXNE: Receive Data register not empty interrupt + * @arg UART_IT_IDLE: Idle line detection interrupt + * @arg UART_IT_PE: Parity Error interrupt + * @arg UART_IT_ERR: Error interrupt(Frame error, noise error, overrun error) + * @retval None + */ +#define UART_IT_MASK 0x0000FFFFU +#define __HAL_UART_ENABLE_IT(__HANDLE__, __INTERRUPT__) ((((__INTERRUPT__) >> 28U) == 1U)? ((__HANDLE__)->Instance->CR1 |= ((__INTERRUPT__) & UART_IT_MASK)): \ + (((__INTERRUPT__) >> 28U) == 2U)? ((__HANDLE__)->Instance->CR2 |= ((__INTERRUPT__) & UART_IT_MASK)): \ + ((__HANDLE__)->Instance->CR3 |= ((__INTERRUPT__) & UART_IT_MASK))) +/** @brief Disable the specified UART interrupt. + * @param __HANDLE__: specifies the UART Handle. + * This parameter can be UARTx where x: 1, 2, 3, 4, 5, 6, 7 or 8 to select the USART or + * UART peripheral. + * @param __INTERRUPT__: specifies the UART interrupt source to disable. + * This parameter can be one of the following values: + * @arg UART_IT_CTS: CTS change interrupt + * @arg UART_IT_LBD: LIN Break detection interrupt + * @arg UART_IT_TXE: Transmit Data Register empty interrupt + * @arg UART_IT_TC: Transmission complete interrupt + * @arg UART_IT_RXNE: Receive Data register not empty interrupt + * @arg UART_IT_IDLE: Idle line detection interrupt + * @arg UART_IT_PE: Parity Error interrupt + * @arg UART_IT_ERR: Error interrupt(Frame error, noise error, overrun error) + * @retval None + */ +#define __HAL_UART_DISABLE_IT(__HANDLE__, __INTERRUPT__) ((((__INTERRUPT__) >> 28U) == 1U)? ((__HANDLE__)->Instance->CR1 &= ~((__INTERRUPT__) & UART_IT_MASK)): \ + (((__INTERRUPT__) >> 28U) == 2U)? ((__HANDLE__)->Instance->CR2 &= ~((__INTERRUPT__) & UART_IT_MASK)): \ + ((__HANDLE__)->Instance->CR3 &= ~ ((__INTERRUPT__) & UART_IT_MASK))) + +/** @brief Checks whether the specified UART interrupt has occurred or not. + * @param __HANDLE__: specifies the UART Handle. + * This parameter can be UARTx where x: 1, 2, 3, 4, 5, 6, 7 or 8 to select the USART or + * UART peripheral. + * @param __IT__: specifies the UART interrupt source to check. + * This parameter can be one of the following values: + * @arg UART_IT_CTS: CTS change interrupt (not available for UART4 and UART5) + * @arg UART_IT_LBD: LIN Break detection interrupt + * @arg UART_IT_TXE: Transmit Data Register empty interrupt + * @arg UART_IT_TC: Transmission complete interrupt + * @arg UART_IT_RXNE: Receive Data register not empty interrupt + * @arg UART_IT_IDLE: Idle line detection interrupt + * @arg USART_IT_ERR: Error interrupt + * @retval The new state of __IT__ (TRUE or FALSE). + */ +#define __HAL_UART_GET_IT_SOURCE(__HANDLE__, __IT__) (((((__IT__) >> 28U) == 1U)? (__HANDLE__)->Instance->CR1:(((((uint32_t)(__IT__)) >> 28U) == 2U)? \ + (__HANDLE__)->Instance->CR2 : (__HANDLE__)->Instance->CR3)) & (((uint32_t)(__IT__)) & UART_IT_MASK)) + +/** @brief Enable CTS flow control + * This macro allows to enable CTS hardware flow control for a given UART instance, + * without need to call HAL_UART_Init() function. + * As involving direct access to UART registers, usage of this macro should be fully endorsed by user. + * @note As macro is expected to be used for modifying CTS Hw flow control feature activation, without need + * for USART instance Deinit/Init, following conditions for macro call should be fulfilled : + * - UART instance should have already been initialised (through call of HAL_UART_Init() ) + * - macro could only be called when corresponding UART instance is disabled (i.e __HAL_UART_DISABLE(__HANDLE__)) + * and should be followed by an Enable macro (i.e __HAL_UART_ENABLE(__HANDLE__)). + * @param __HANDLE__: specifies the UART Handle. + * The Handle Instance can be USART1, USART2 or LPUART. + * @retval None + */ +#define __HAL_UART_HWCONTROL_CTS_ENABLE(__HANDLE__) \ + do{ \ + SET_BIT((__HANDLE__)->Instance->CR3, USART_CR3_CTSE); \ + (__HANDLE__)->Init.HwFlowCtl |= USART_CR3_CTSE; \ + } while(0U) + +/** @brief Disable CTS flow control + * This macro allows to disable CTS hardware flow control for a given UART instance, + * without need to call HAL_UART_Init() function. + * As involving direct access to UART registers, usage of this macro should be fully endorsed by user. + * @note As macro is expected to be used for modifying CTS Hw flow control feature activation, without need + * for USART instance Deinit/Init, following conditions for macro call should be fulfilled : + * - UART instance should have already been initialised (through call of HAL_UART_Init() ) + * - macro could only be called when corresponding UART instance is disabled (i.e __HAL_UART_DISABLE(__HANDLE__)) + * and should be followed by an Enable macro (i.e __HAL_UART_ENABLE(__HANDLE__)). + * @param __HANDLE__: specifies the UART Handle. + * The Handle Instance can be USART1, USART2 or LPUART. + * @retval None + */ +#define __HAL_UART_HWCONTROL_CTS_DISABLE(__HANDLE__) \ + do{ \ + CLEAR_BIT((__HANDLE__)->Instance->CR3, USART_CR3_CTSE); \ + (__HANDLE__)->Init.HwFlowCtl &= ~(USART_CR3_CTSE); \ + } while(0U) + +/** @brief Enable RTS flow control + * This macro allows to enable RTS hardware flow control for a given UART instance, + * without need to call HAL_UART_Init() function. + * As involving direct access to UART registers, usage of this macro should be fully endorsed by user. + * @note As macro is expected to be used for modifying RTS Hw flow control feature activation, without need + * for USART instance Deinit/Init, following conditions for macro call should be fulfilled : + * - UART instance should have already been initialised (through call of HAL_UART_Init() ) + * - macro could only be called when corresponding UART instance is disabled (i.e __HAL_UART_DISABLE(__HANDLE__)) + * and should be followed by an Enable macro (i.e __HAL_UART_ENABLE(__HANDLE__)). + * @param __HANDLE__: specifies the UART Handle. + * The Handle Instance can be USART1, USART2 or LPUART. + * @retval None + */ +#define __HAL_UART_HWCONTROL_RTS_ENABLE(__HANDLE__) \ + do{ \ + SET_BIT((__HANDLE__)->Instance->CR3, USART_CR3_RTSE); \ + (__HANDLE__)->Init.HwFlowCtl |= USART_CR3_RTSE; \ + } while(0U) + +/** @brief Disable RTS flow control + * This macro allows to disable RTS hardware flow control for a given UART instance, + * without need to call HAL_UART_Init() function. + * As involving direct access to UART registers, usage of this macro should be fully endorsed by user. + * @note As macro is expected to be used for modifying RTS Hw flow control feature activation, without need + * for USART instance Deinit/Init, following conditions for macro call should be fulfilled : + * - UART instance should have already been initialised (through call of HAL_UART_Init() ) + * - macro could only be called when corresponding UART instance is disabled (i.e __HAL_UART_DISABLE(__HANDLE__)) + * and should be followed by an Enable macro (i.e __HAL_UART_ENABLE(__HANDLE__)). + * @param __HANDLE__: specifies the UART Handle. + * The Handle Instance can be USART1, USART2 or LPUART. + * @retval None + */ +#define __HAL_UART_HWCONTROL_RTS_DISABLE(__HANDLE__) \ + do{ \ + CLEAR_BIT((__HANDLE__)->Instance->CR3, USART_CR3_RTSE);\ + (__HANDLE__)->Init.HwFlowCtl &= ~(USART_CR3_RTSE); \ + } while(0U) + +/** @brief macros to enables the UART's one bit sample method + * @param __HANDLE__: specifies the UART Handle. + * @retval None + */ +#define __HAL_UART_ONE_BIT_SAMPLE_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->CR3|= USART_CR3_ONEBIT) + +/** @brief macros to disables the UART's one bit sample method + * @param __HANDLE__: specifies the UART Handle. + * @retval None + */ +#define __HAL_UART_ONE_BIT_SAMPLE_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->CR3 &= (uint16_t)~((uint16_t)USART_CR3_ONEBIT)) + +/** @brief Enable UART + * @param __HANDLE__: specifies the UART Handle. + * @retval None + */ +#define __HAL_UART_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->CR1 |= USART_CR1_UE) + +/** @brief Disable UART + * @param __HANDLE__: specifies the UART Handle. + * @retval None + */ +#define __HAL_UART_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->CR1 &= ~USART_CR1_UE) +/** + * @} + */ + +/* Exported functions --------------------------------------------------------*/ +/** @addtogroup UART_Exported_Functions + * @{ + */ + +/** @addtogroup UART_Exported_Functions_Group1 + * @{ + */ +/* Initialization/de-initialization functions **********************************/ +HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart); +HAL_StatusTypeDef HAL_HalfDuplex_Init(UART_HandleTypeDef *huart); +HAL_StatusTypeDef HAL_LIN_Init(UART_HandleTypeDef *huart, uint32_t BreakDetectLength); +HAL_StatusTypeDef HAL_MultiProcessor_Init(UART_HandleTypeDef *huart, uint8_t Address, uint32_t WakeUpMethod); +HAL_StatusTypeDef HAL_UART_DeInit (UART_HandleTypeDef *huart); +void HAL_UART_MspInit(UART_HandleTypeDef *huart); +void HAL_UART_MspDeInit(UART_HandleTypeDef *huart); +/** + * @} + */ + +/** @addtogroup UART_Exported_Functions_Group2 + * @{ + */ +/* IO operation functions *******************************************************/ +HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout); +HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout); +HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size); +HAL_StatusTypeDef HAL_UART_DMAPause(UART_HandleTypeDef *huart); +HAL_StatusTypeDef HAL_UART_DMAResume(UART_HandleTypeDef *huart); +HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart); +/* Transfer Abort functions */ +HAL_StatusTypeDef HAL_UART_Abort(UART_HandleTypeDef *huart); +HAL_StatusTypeDef HAL_UART_AbortTransmit(UART_HandleTypeDef *huart); +HAL_StatusTypeDef HAL_UART_AbortReceive(UART_HandleTypeDef *huart); +HAL_StatusTypeDef HAL_UART_Abort_IT(UART_HandleTypeDef *huart); +HAL_StatusTypeDef HAL_UART_AbortTransmit_IT(UART_HandleTypeDef *huart); +HAL_StatusTypeDef HAL_UART_AbortReceive_IT(UART_HandleTypeDef *huart); + +void HAL_UART_IRQHandler(UART_HandleTypeDef *huart); +void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart); +void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart); +void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart); +void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart); +void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart); +void HAL_UART_AbortCpltCallback (UART_HandleTypeDef *huart); +void HAL_UART_AbortTransmitCpltCallback (UART_HandleTypeDef *huart); +void HAL_UART_AbortReceiveCpltCallback (UART_HandleTypeDef *huart); +/** + * @} + */ + +/** @addtogroup UART_Exported_Functions_Group3 + * @{ + */ +/* Peripheral Control functions ************************************************/ +HAL_StatusTypeDef HAL_LIN_SendBreak(UART_HandleTypeDef *huart); +HAL_StatusTypeDef HAL_MultiProcessor_EnterMuteMode(UART_HandleTypeDef *huart); +HAL_StatusTypeDef HAL_MultiProcessor_ExitMuteMode(UART_HandleTypeDef *huart); +HAL_StatusTypeDef HAL_HalfDuplex_EnableTransmitter(UART_HandleTypeDef *huart); +HAL_StatusTypeDef HAL_HalfDuplex_EnableReceiver(UART_HandleTypeDef *huart); +/** + * @} + */ + +/** @addtogroup UART_Exported_Functions_Group4 + * @{ + */ +/* Peripheral State functions **************************************************/ +HAL_UART_StateTypeDef HAL_UART_GetState(UART_HandleTypeDef *huart); +uint32_t HAL_UART_GetError(UART_HandleTypeDef *huart); +/** + * @} + */ + +/** + * @} + */ +/* Private types -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private constants ---------------------------------------------------------*/ +/** @defgroup UART_Private_Constants UART Private Constants + * @{ + */ +/** @brief UART interruptions flag mask + * + */ +#define UART_CR1_REG_INDEX 1U +#define UART_CR2_REG_INDEX 2U +#define UART_CR3_REG_INDEX 3U +/** + * @} + */ + +/* Private macros ------------------------------------------------------------*/ +/** @defgroup UART_Private_Macros UART Private Macros + * @{ + */ +#define IS_UART_WORD_LENGTH(LENGTH) (((LENGTH) == UART_WORDLENGTH_8B) || \ + ((LENGTH) == UART_WORDLENGTH_9B)) +#define IS_UART_LIN_WORD_LENGTH(LENGTH) (((LENGTH) == UART_WORDLENGTH_8B)) +#define IS_UART_STOPBITS(STOPBITS) (((STOPBITS) == UART_STOPBITS_1) || \ + ((STOPBITS) == UART_STOPBITS_2)) +#define IS_UART_PARITY(PARITY) (((PARITY) == UART_PARITY_NONE) || \ + ((PARITY) == UART_PARITY_EVEN) || \ + ((PARITY) == UART_PARITY_ODD)) +#define IS_UART_HARDWARE_FLOW_CONTROL(CONTROL)\ + (((CONTROL) == UART_HWCONTROL_NONE) || \ + ((CONTROL) == UART_HWCONTROL_RTS) || \ + ((CONTROL) == UART_HWCONTROL_CTS) || \ + ((CONTROL) == UART_HWCONTROL_RTS_CTS)) +#define IS_UART_MODE(MODE) ((((MODE) & 0x0000FFF3U) == 0x00U) && ((MODE) != 0x00U)) +#define IS_UART_STATE(STATE) (((STATE) == UART_STATE_DISABLE) || \ + ((STATE) == UART_STATE_ENABLE)) +#define IS_UART_OVERSAMPLING(SAMPLING) (((SAMPLING) == UART_OVERSAMPLING_16) || \ + ((SAMPLING) == UART_OVERSAMPLING_8)) +#define IS_UART_LIN_OVERSAMPLING(SAMPLING) (((SAMPLING) == UART_OVERSAMPLING_16)) +#define IS_UART_LIN_BREAK_DETECT_LENGTH(LENGTH) (((LENGTH) == UART_LINBREAKDETECTLENGTH_10B) || \ + ((LENGTH) == UART_LINBREAKDETECTLENGTH_11B)) +#define IS_UART_WAKEUPMETHOD(WAKEUP) (((WAKEUP) == UART_WAKEUPMETHOD_IDLELINE) || \ + ((WAKEUP) == UART_WAKEUPMETHOD_ADDRESSMARK)) +#define IS_UART_BAUDRATE(BAUDRATE) ((BAUDRATE) < 10500001U) +#define IS_UART_ADDRESS(ADDRESS) ((ADDRESS) <= 0x0FU) + +#define UART_DIV_SAMPLING16(_PCLK_, _BAUD_) (((_PCLK_)*25U)/(4U*(_BAUD_))) +#define UART_DIVMANT_SAMPLING16(_PCLK_, _BAUD_) (UART_DIV_SAMPLING16((_PCLK_), (_BAUD_))/100U) +#define UART_DIVFRAQ_SAMPLING16(_PCLK_, _BAUD_) (((UART_DIV_SAMPLING16((_PCLK_), (_BAUD_)) - (UART_DIVMANT_SAMPLING16((_PCLK_), (_BAUD_)) * 100U)) * 16U + 50U) / 100U) +/* UART BRR = mantissa + overflow + fraction + = (UART DIVMANT << 4) + (UART DIVFRAQ & 0xF0) + (UART DIVFRAQ & 0x0FU) */ +#define UART_BRR_SAMPLING16(_PCLK_, _BAUD_) (((UART_DIVMANT_SAMPLING16((_PCLK_), (_BAUD_)) << 4U) + \ + (UART_DIVFRAQ_SAMPLING16((_PCLK_), (_BAUD_)) & 0xF0U)) + \ + (UART_DIVFRAQ_SAMPLING16((_PCLK_), (_BAUD_)) & 0x0FU)) + +#define UART_DIV_SAMPLING8(_PCLK_, _BAUD_) (((_PCLK_)*25U)/(2U*(_BAUD_))) +#define UART_DIVMANT_SAMPLING8(_PCLK_, _BAUD_) (UART_DIV_SAMPLING8((_PCLK_), (_BAUD_))/100U) +#define UART_DIVFRAQ_SAMPLING8(_PCLK_, _BAUD_) (((UART_DIV_SAMPLING8((_PCLK_), (_BAUD_)) - (UART_DIVMANT_SAMPLING8((_PCLK_), (_BAUD_)) * 100U)) * 8U + 50U) / 100U) +/* UART BRR = mantissa + overflow + fraction + = (UART DIVMANT << 4) + ((UART DIVFRAQ & 0xF8) << 1) + (UART DIVFRAQ & 0x07U) */ +#define UART_BRR_SAMPLING8(_PCLK_, _BAUD_) (((UART_DIVMANT_SAMPLING8((_PCLK_), (_BAUD_)) << 4U) + \ + ((UART_DIVFRAQ_SAMPLING8((_PCLK_), (_BAUD_)) & 0xF8U) << 1U)) + \ + (UART_DIVFRAQ_SAMPLING8((_PCLK_), (_BAUD_)) & 0x07U)) + +/** + * @} + */ + +/* Private functions ---------------------------------------------------------*/ +/** @defgroup UART_Private_Functions UART Private Functions + * @{ + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_UART_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c b/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c new file mode 100644 index 00000000..40f28ea8 --- /dev/null +++ b/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c @@ -0,0 +1,2539 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_uart.c + * @author MCD Application Team + * @version V1.7.1 + * @date 14-April-2017 + * @brief UART HAL module driver. + * This file provides firmware functions to manage the following + * functionalities of the Universal Asynchronous Receiver Transmitter (UART) peripheral: + * + Initialization and de-initialization functions + * + IO operation functions + * + Peripheral Control functions + * + Peripheral State and Errors functions + * + @verbatim + ============================================================================== + ##### How to use this driver ##### + ============================================================================== + [..] + The UART HAL driver can be used as follows: + + (#) Declare a UART_HandleTypeDef handle structure. + + (#) Initialize the UART low level resources by implementing the HAL_UART_MspInit() API: + (##) Enable the USARTx interface clock. + (##) UART pins configuration: + (+++) Enable the clock for the UART GPIOs. + (+++) Configure these UART pins as alternate function pull-up. + (##) NVIC configuration if you need to use interrupt process (HAL_UART_Transmit_IT() + and HAL_UART_Receive_IT() APIs): + (+++) Configure the USARTx interrupt priority. + (+++) Enable the NVIC USART IRQ handle. + (##) DMA Configuration if you need to use DMA process (HAL_UART_Transmit_DMA() + and HAL_UART_Receive_DMA() APIs): + (+++) Declare a DMA handle structure for the Tx/Rx stream. + (+++) Enable the DMAx interface clock. + (+++) Configure the declared DMA handle structure with the required + Tx/Rx parameters. + (+++) Configure the DMA Tx/Rx Stream. + (+++) Associate the initialized DMA handle to the UART DMA Tx/Rx handle. + (+++) Configure the priority and enable the NVIC for the transfer complete + interrupt on the DMA Tx/Rx Stream. + + (#) Program the Baud Rate, Word Length, Stop Bit, Parity, Hardware + flow control and Mode(Receiver/Transmitter) in the Init structure. + + (#) For the UART asynchronous mode, initialize the UART registers by calling + the HAL_UART_Init() API. + + (#) For the UART Half duplex mode, initialize the UART registers by calling + the HAL_HalfDuplex_Init() API. + + (#) For the LIN mode, initialize the UART registers by calling the HAL_LIN_Init() API. + + (#) For the Multi-Processor mode, initialize the UART registers by calling + the HAL_MultiProcessor_Init() API. + + [..] + (@) The specific UART interrupts (Transmission complete interrupt, + RXNE interrupt and Error Interrupts) will be managed using the macros + __HAL_UART_ENABLE_IT() and __HAL_UART_DISABLE_IT() inside the transmit + and receive process. + + [..] + (@) These APIs (HAL_UART_Init() and HAL_HalfDuplex_Init()) configure also the + low level Hardware GPIO, CLOCK, CORTEX...etc) by calling the customized + HAL_UART_MspInit() API. + + [..] + Three operation modes are available within this driver : + + *** Polling mode IO operation *** + ================================= + [..] + (+) Send an amount of data in blocking mode using HAL_UART_Transmit() + (+) Receive an amount of data in blocking mode using HAL_UART_Receive() + + *** Interrupt mode IO operation *** + =================================== + [..] + (+) Send an amount of data in non blocking mode using HAL_UART_Transmit_IT() + (+) At transmission end of transfer HAL_UART_TxCpltCallback is executed and user can + add his own code by customization of function pointer HAL_UART_TxCpltCallback + (+) Receive an amount of data in non blocking mode using HAL_UART_Receive_IT() + (+) At reception end of transfer HAL_UART_RxCpltCallback is executed and user can + add his own code by customization of function pointer HAL_UART_RxCpltCallback + (+) In case of transfer Error, HAL_UART_ErrorCallback() function is executed and user can + add his own code by customization of function pointer HAL_UART_ErrorCallback + + *** DMA mode IO operation *** + ============================== + [..] + (+) Send an amount of data in non blocking mode (DMA) using HAL_UART_Transmit_DMA() + (+) At transmission end of half transfer HAL_UART_TxHalfCpltCallback is executed and user can + add his own code by customization of function pointer HAL_UART_TxHalfCpltCallback + (+) At transmission end of transfer HAL_UART_TxCpltCallback is executed and user can + add his own code by customization of function pointer HAL_UART_TxCpltCallback + (+) Receive an amount of data in non blocking mode (DMA) using HAL_UART_Receive_DMA() + (+) At reception end of half transfer HAL_UART_RxHalfCpltCallback is executed and user can + add his own code by customization of function pointer HAL_UART_RxHalfCpltCallback + (+) At reception end of transfer HAL_UART_RxCpltCallback is executed and user can + add his own code by customization of function pointer HAL_UART_RxCpltCallback + (+) In case of transfer Error, HAL_UART_ErrorCallback() function is executed and user can + add his own code by customization of function pointer HAL_UART_ErrorCallback + (+) Pause the DMA Transfer using HAL_UART_DMAPause() + (+) Resume the DMA Transfer using HAL_UART_DMAResume() + (+) Stop the DMA Transfer using HAL_UART_DMAStop() + + *** UART HAL driver macros list *** + ============================================= + [..] + Below the list of most used macros in UART HAL driver. + + (+) __HAL_UART_ENABLE: Enable the UART peripheral + (+) __HAL_UART_DISABLE: Disable the UART peripheral + (+) __HAL_UART_GET_FLAG : Check whether the specified UART flag is set or not + (+) __HAL_UART_CLEAR_FLAG : Clear the specified UART pending flag + (+) __HAL_UART_ENABLE_IT: Enable the specified UART interrupt + (+) __HAL_UART_DISABLE_IT: Disable the specified UART interrupt + (+) __HAL_UART_GET_IT_SOURCE: Check whether the specified UART interrupt has occurred or not + + [..] + (@) You can refer to the UART HAL driver header file for more useful macros + + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal.h" + +/** @addtogroup STM32F4xx_HAL_Driver + * @{ + */ + +/** @defgroup UART UART + * @brief HAL UART module driver + * @{ + */ +#ifdef HAL_UART_MODULE_ENABLED + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/** @addtogroup UART_Private_Constants + * @{ + */ +/** + * @} + */ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/** @addtogroup UART_Private_Functions UART Private Functions + * @{ + */ +static void UART_EndTxTransfer(UART_HandleTypeDef *huart); +static void UART_EndRxTransfer(UART_HandleTypeDef *huart); +static void UART_DMATransmitCplt(DMA_HandleTypeDef *hdma); +static void UART_DMAReceiveCplt(DMA_HandleTypeDef *hdma); +static void UART_DMATxHalfCplt(DMA_HandleTypeDef *hdma); +static void UART_DMARxHalfCplt(DMA_HandleTypeDef *hdma); +static void UART_DMAError(DMA_HandleTypeDef *hdma); +static void UART_DMAAbortOnError(DMA_HandleTypeDef *hdma); +static void UART_DMATxAbortCallback(DMA_HandleTypeDef *hdma); +static void UART_DMARxAbortCallback(DMA_HandleTypeDef *hdma); +static void UART_DMATxOnlyAbortCallback(DMA_HandleTypeDef *hdma); +static void UART_DMARxOnlyAbortCallback(DMA_HandleTypeDef *hdma); +static HAL_StatusTypeDef UART_Transmit_IT(UART_HandleTypeDef *huart); +static HAL_StatusTypeDef UART_EndTransmit_IT(UART_HandleTypeDef *huart); +static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart); +static HAL_StatusTypeDef UART_WaitOnFlagUntilTimeout(UART_HandleTypeDef *huart, uint32_t Flag, FlagStatus Status, uint32_t Tickstart, uint32_t Timeout); +static void UART_SetConfig (UART_HandleTypeDef *huart); +/** + * @} + */ + +/* Exported functions ---------------------------------------------------------*/ +/** @defgroup UART_Exported_Functions UART Exported Functions + * @{ + */ + +/** @defgroup UART_Exported_Functions_Group1 Initialization and de-initialization functions + * @brief Initialization and Configuration functions + * +@verbatim +=============================================================================== + ##### Initialization and Configuration functions ##### + =============================================================================== + [..] + This subsection provides a set of functions allowing to initialize the USARTx or the UARTy + in asynchronous mode. + (+) For the asynchronous mode only these parameters can be configured: + (++) Baud Rate + (++) Word Length + (++) Stop Bit + (++) Parity: If the parity is enabled, then the MSB bit of the data written + in the data register is transmitted but is changed by the parity bit. + Depending on the frame length defined by the M bit (8-bits or 9-bits), + please refer to Reference manual for possible UART frame formats. + (++) Hardware flow control + (++) Receiver/transmitter modes + (++) Over Sampling Method + [..] + The HAL_UART_Init(), HAL_HalfDuplex_Init(), HAL_LIN_Init() and HAL_MultiProcessor_Init() APIs + follow respectively the UART asynchronous, UART Half duplex, LIN and Multi-Processor + configuration procedures (details for the procedures are available in reference manual (RM0329)). + +@endverbatim + * @{ + */ + +/** + * @brief Initializes the UART mode according to the specified parameters in + * the UART_InitTypeDef and create the associated handle. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart) +{ + /* Check the UART handle allocation */ + if(huart == NULL) + { + return HAL_ERROR; + } + + /* Check the parameters */ + if(huart->Init.HwFlowCtl != UART_HWCONTROL_NONE) + { + /* The hardware flow control is available only for USART1, USART2, USART3 and USART6 */ + assert_param(IS_UART_HWFLOW_INSTANCE(huart->Instance)); + assert_param(IS_UART_HARDWARE_FLOW_CONTROL(huart->Init.HwFlowCtl)); + } + else + { + assert_param(IS_UART_INSTANCE(huart->Instance)); + } + assert_param(IS_UART_WORD_LENGTH(huart->Init.WordLength)); + assert_param(IS_UART_OVERSAMPLING(huart->Init.OverSampling)); + + if(huart->gState == HAL_UART_STATE_RESET) + { + /* Allocate lock resource and initialize it */ + huart->Lock = HAL_UNLOCKED; + /* Init the low level hardware */ + HAL_UART_MspInit(huart); + } + + huart->gState = HAL_UART_STATE_BUSY; + + /* Disable the peripheral */ + __HAL_UART_DISABLE(huart); + + /* Set the UART Communication parameters */ + UART_SetConfig(huart); + + /* In asynchronous mode, the following bits must be kept cleared: + - LINEN and CLKEN bits in the USART_CR2 register, + - SCEN, HDSEL and IREN bits in the USART_CR3 register.*/ + CLEAR_BIT(huart->Instance->CR2, (USART_CR2_LINEN | USART_CR2_CLKEN)); + CLEAR_BIT(huart->Instance->CR3, (USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN)); + + /* Enable the peripheral */ + __HAL_UART_ENABLE(huart); + + /* Initialize the UART state */ + huart->ErrorCode = HAL_UART_ERROR_NONE; + huart->gState= HAL_UART_STATE_READY; + huart->RxState= HAL_UART_STATE_READY; + + return HAL_OK; +} + +/** + * @brief Initializes the half-duplex mode according to the specified + * parameters in the UART_InitTypeDef and create the associated handle. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_HalfDuplex_Init(UART_HandleTypeDef *huart) +{ + /* Check the UART handle allocation */ + if(huart == NULL) + { + return HAL_ERROR; + } + + /* Check the parameters */ + assert_param(IS_UART_INSTANCE(huart->Instance)); + assert_param(IS_UART_WORD_LENGTH(huart->Init.WordLength)); + assert_param(IS_UART_OVERSAMPLING(huart->Init.OverSampling)); + + if(huart->gState == HAL_UART_STATE_RESET) + { + /* Allocate lock resource and initialize it */ + huart->Lock = HAL_UNLOCKED; + /* Init the low level hardware */ + HAL_UART_MspInit(huart); + } + + huart->gState = HAL_UART_STATE_BUSY; + + /* Disable the peripheral */ + __HAL_UART_DISABLE(huart); + + /* Set the UART Communication parameters */ + UART_SetConfig(huart); + + /* In half-duplex mode, the following bits must be kept cleared: + - LINEN and CLKEN bits in the USART_CR2 register, + - SCEN and IREN bits in the USART_CR3 register.*/ + CLEAR_BIT(huart->Instance->CR2, (USART_CR2_LINEN | USART_CR2_CLKEN)); + CLEAR_BIT(huart->Instance->CR3, (USART_CR3_IREN | USART_CR3_SCEN)); + + /* Enable the Half-Duplex mode by setting the HDSEL bit in the CR3 register */ + SET_BIT(huart->Instance->CR3, USART_CR3_HDSEL); + + /* Enable the peripheral */ + __HAL_UART_ENABLE(huart); + + /* Initialize the UART state*/ + huart->ErrorCode = HAL_UART_ERROR_NONE; + huart->gState= HAL_UART_STATE_READY; + huart->RxState= HAL_UART_STATE_READY; + + return HAL_OK; +} + +/** + * @brief Initializes the LIN mode according to the specified + * parameters in the UART_InitTypeDef and create the associated handle. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @param BreakDetectLength: Specifies the LIN break detection length. + * This parameter can be one of the following values: + * @arg UART_LINBREAKDETECTLENGTH_10B: 10-bit break detection + * @arg UART_LINBREAKDETECTLENGTH_11B: 11-bit break detection + * @retval HAL status + */ +HAL_StatusTypeDef HAL_LIN_Init(UART_HandleTypeDef *huart, uint32_t BreakDetectLength) +{ + /* Check the UART handle allocation */ + if(huart == NULL) + { + return HAL_ERROR; + } + + /* Check the parameters */ + assert_param(IS_UART_INSTANCE(huart->Instance)); + assert_param(IS_UART_LIN_BREAK_DETECT_LENGTH(BreakDetectLength)); + assert_param(IS_UART_LIN_WORD_LENGTH(huart->Init.WordLength)); + assert_param(IS_UART_LIN_OVERSAMPLING(huart->Init.OverSampling)); + + if(huart->gState == HAL_UART_STATE_RESET) + { + /* Allocate lock resource and initialize it */ + huart->Lock = HAL_UNLOCKED; + /* Init the low level hardware */ + HAL_UART_MspInit(huart); + } + + huart->gState = HAL_UART_STATE_BUSY; + + /* Disable the peripheral */ + __HAL_UART_DISABLE(huart); + + /* Set the UART Communication parameters */ + UART_SetConfig(huart); + + /* In LIN mode, the following bits must be kept cleared: + - LINEN and CLKEN bits in the USART_CR2 register, + - SCEN and IREN bits in the USART_CR3 register.*/ + CLEAR_BIT(huart->Instance->CR2, USART_CR2_CLKEN); + CLEAR_BIT(huart->Instance->CR3, (USART_CR3_HDSEL | USART_CR3_IREN | USART_CR3_SCEN)); + + /* Enable the LIN mode by setting the LINEN bit in the CR2 register */ + SET_BIT(huart->Instance->CR2, USART_CR2_LINEN); + + /* Set the USART LIN Break detection length. */ + CLEAR_BIT(huart->Instance->CR2, USART_CR2_LBDL); + SET_BIT(huart->Instance->CR2, BreakDetectLength); + + /* Enable the peripheral */ + __HAL_UART_ENABLE(huart); + + /* Initialize the UART state*/ + huart->ErrorCode = HAL_UART_ERROR_NONE; + huart->gState= HAL_UART_STATE_READY; + huart->RxState= HAL_UART_STATE_READY; + + return HAL_OK; +} + +/** + * @brief Initializes the Multi-Processor mode according to the specified + * parameters in the UART_InitTypeDef and create the associated handle. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @param Address: USART address + * @param WakeUpMethod: specifies the USART wake-up method. + * This parameter can be one of the following values: + * @arg UART_WAKEUPMETHOD_IDLELINE: Wake-up by an idle line detection + * @arg UART_WAKEUPMETHOD_ADDRESSMARK: Wake-up by an address mark + * @retval HAL status + */ +HAL_StatusTypeDef HAL_MultiProcessor_Init(UART_HandleTypeDef *huart, uint8_t Address, uint32_t WakeUpMethod) +{ + /* Check the UART handle allocation */ + if(huart == NULL) + { + return HAL_ERROR; + } + + /* Check the parameters */ + assert_param(IS_UART_INSTANCE(huart->Instance)); + assert_param(IS_UART_WAKEUPMETHOD(WakeUpMethod)); + assert_param(IS_UART_ADDRESS(Address)); + assert_param(IS_UART_WORD_LENGTH(huart->Init.WordLength)); + assert_param(IS_UART_OVERSAMPLING(huart->Init.OverSampling)); + + if(huart->gState == HAL_UART_STATE_RESET) + { + /* Allocate lock resource and initialize it */ + huart->Lock = HAL_UNLOCKED; + /* Init the low level hardware */ + HAL_UART_MspInit(huart); + } + + huart->gState = HAL_UART_STATE_BUSY; + + /* Disable the peripheral */ + __HAL_UART_DISABLE(huart); + + /* Set the UART Communication parameters */ + UART_SetConfig(huart); + + /* In Multi-Processor mode, the following bits must be kept cleared: + - LINEN and CLKEN bits in the USART_CR2 register, + - SCEN, HDSEL and IREN bits in the USART_CR3 register */ + CLEAR_BIT(huart->Instance->CR2, (USART_CR2_LINEN | USART_CR2_CLKEN)); + CLEAR_BIT(huart->Instance->CR3, (USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN)); + + /* Clear the USART address */ + CLEAR_BIT(huart->Instance->CR2, USART_CR2_ADD); + /* Set the USART address node */ + SET_BIT(huart->Instance->CR2, Address); + + /* Set the wake up method by setting the WAKE bit in the CR1 register */ + CLEAR_BIT(huart->Instance->CR1, USART_CR1_WAKE); + SET_BIT(huart->Instance->CR1, WakeUpMethod); + + /* Enable the peripheral */ + __HAL_UART_ENABLE(huart); + + /* Initialize the UART state */ + huart->ErrorCode = HAL_UART_ERROR_NONE; + huart->gState= HAL_UART_STATE_READY; + huart->RxState= HAL_UART_STATE_READY; + + return HAL_OK; +} + +/** + * @brief DeInitializes the UART peripheral. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_UART_DeInit(UART_HandleTypeDef *huart) +{ + /* Check the UART handle allocation */ + if(huart == NULL) + { + return HAL_ERROR; + } + + /* Check the parameters */ + assert_param(IS_UART_INSTANCE(huart->Instance)); + + huart->gState = HAL_UART_STATE_BUSY; + + /* DeInit the low level hardware */ + HAL_UART_MspDeInit(huart); + + huart->ErrorCode = HAL_UART_ERROR_NONE; + huart->gState = HAL_UART_STATE_RESET; + huart->RxState = HAL_UART_STATE_RESET; + + /* Process Lock */ + __HAL_UNLOCK(huart); + + return HAL_OK; +} + +/** + * @brief UART MSP Init. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval None + */ + __weak void HAL_UART_MspInit(UART_HandleTypeDef *huart) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(huart); + /* NOTE: This function Should not be modified, when the callback is needed, + the HAL_UART_MspInit could be implemented in the user file + */ +} + +/** + * @brief UART MSP DeInit. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval None + */ + __weak void HAL_UART_MspDeInit(UART_HandleTypeDef *huart) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(huart); + /* NOTE: This function Should not be modified, when the callback is needed, + the HAL_UART_MspDeInit could be implemented in the user file + */ +} + +/** + * @} + */ + +/** @defgroup UART_Exported_Functions_Group2 IO operation functions + * @brief UART Transmit and Receive functions + * +@verbatim + ============================================================================== + ##### IO operation functions ##### + ============================================================================== + [..] + This subsection provides a set of functions allowing to manage the UART asynchronous + and Half duplex data transfers. + + (#) There are two modes of transfer: + (++) Blocking mode: The communication is performed in polling mode. + The HAL status of all data processing is returned by the same function + after finishing transfer. + (++) Non blocking mode: The communication is performed using Interrupts + or DMA, these APIs return the HAL status. + The end of the data processing will be indicated through the + dedicated UART IRQ when using Interrupt mode or the DMA IRQ when + using DMA mode. + The HAL_UART_TxCpltCallback(), HAL_UART_RxCpltCallback() user callbacks + will be executed respectively at the end of the transmit or receive process. + The HAL_UART_ErrorCallback() user callback will be executed when + a communication error is detected. + + (#) Blocking mode APIs are: + (++) HAL_UART_Transmit() + (++) HAL_UART_Receive() + + (#) Non Blocking mode APIs with Interrupt are: + (++) HAL_UART_Transmit_IT() + (++) HAL_UART_Receive_IT() + (++) HAL_UART_IRQHandler() + + (#) Non Blocking mode functions with DMA are: + (++) HAL_UART_Transmit_DMA() + (++) HAL_UART_Receive_DMA() + + (#) A set of Transfer Complete Callbacks are provided in non blocking mode: + (++) HAL_UART_TxCpltCallback() + (++) HAL_UART_RxCpltCallback() + (++) HAL_UART_ErrorCallback() + + [..] + (@) In the Half duplex communication, it is forbidden to run the transmit + and receive process in parallel, the UART state HAL_UART_STATE_BUSY_TX_RX + can't be useful. + +@endverbatim + * @{ + */ + +/** + * @brief Sends an amount of data in blocking mode. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @param pData: Pointer to data buffer + * @param Size: Amount of data to be sent + * @param Timeout: Timeout duration + * @retval HAL status + */ +HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout) +{ + uint16_t* tmp; + uint32_t tickstart = 0U; + + /* Check that a Tx process is not already ongoing */ + if(huart->gState == HAL_UART_STATE_READY) + { + if((pData == NULL ) || (Size == 0)) + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(huart); + + huart->ErrorCode = HAL_UART_ERROR_NONE; + huart->gState = HAL_UART_STATE_BUSY_TX; + + /* Init tickstart for timeout managment */ + tickstart = HAL_GetTick(); + + huart->TxXferSize = Size; + huart->TxXferCount = Size; + while(huart->TxXferCount > 0U) + { + huart->TxXferCount--; + if(huart->Init.WordLength == UART_WORDLENGTH_9B) + { + if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK) + { + return HAL_TIMEOUT; + } + tmp = (uint16_t*) pData; + huart->Instance->DR = (*tmp & (uint16_t)0x01FF); + if(huart->Init.Parity == UART_PARITY_NONE) + { + pData +=2U; + } + else + { + pData +=1U; + } + } + else + { + if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK) + { + return HAL_TIMEOUT; + } + huart->Instance->DR = (*pData++ & (uint8_t)0xFF); + } + } + + if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TC, RESET, tickstart, Timeout) != HAL_OK) + { + return HAL_TIMEOUT; + } + + /* At end of Tx process, restore huart->gState to Ready */ + huart->gState = HAL_UART_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(huart); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Receives an amount of data in blocking mode. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @param pData: Pointer to data buffer + * @param Size: Amount of data to be received + * @param Timeout: Timeout duration + * @retval HAL status + */ +HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout) +{ + uint16_t* tmp; + uint32_t tickstart = 0U; + + /* Check that a Rx process is not already ongoing */ + if(huart->RxState == HAL_UART_STATE_READY) + { + if((pData == NULL ) || (Size == 0)) + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(huart); + + huart->ErrorCode = HAL_UART_ERROR_NONE; + huart->RxState = HAL_UART_STATE_BUSY_RX; + + /* Init tickstart for timeout managment */ + tickstart = HAL_GetTick(); + + huart->RxXferSize = Size; + huart->RxXferCount = Size; + + /* Check the remain data to be received */ + while(huart->RxXferCount > 0U) + { + huart->RxXferCount--; + if(huart->Init.WordLength == UART_WORDLENGTH_9B) + { + if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK) + { + return HAL_TIMEOUT; + } + tmp = (uint16_t*) pData; + if(huart->Init.Parity == UART_PARITY_NONE) + { + *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF); + pData +=2U; + } + else + { + *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF); + pData +=1U; + } + + } + else + { + if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK) + { + return HAL_TIMEOUT; + } + if(huart->Init.Parity == UART_PARITY_NONE) + { + *pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF); + } + else + { + *pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F); + } + + } + } + + /* At end of Rx process, restore huart->RxState to Ready */ + huart->RxState = HAL_UART_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(huart); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Sends an amount of data in non blocking mode. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @param pData: Pointer to data buffer + * @param Size: Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) +{ + /* Check that a Tx process is not already ongoing */ + if(huart->gState == HAL_UART_STATE_READY) + { + if((pData == NULL ) || (Size == 0)) + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(huart); + + huart->pTxBuffPtr = pData; + huart->TxXferSize = Size; + huart->TxXferCount = Size; + + huart->ErrorCode = HAL_UART_ERROR_NONE; + huart->gState = HAL_UART_STATE_BUSY_TX; + + /* Process Unlocked */ + __HAL_UNLOCK(huart); + + /* Enable the UART Transmit data register empty Interrupt */ + SET_BIT(huart->Instance->CR1, USART_CR1_TXEIE); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Receives an amount of data in non blocking mode + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @param pData: Pointer to data buffer + * @param Size: Amount of data to be received + * @retval HAL status + */ +HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) +{ + /* Check that a Rx process is not already ongoing */ + if(huart->RxState == HAL_UART_STATE_READY) + { + if((pData == NULL ) || (Size == 0)) + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(huart); + + huart->pRxBuffPtr = pData; + huart->RxXferSize = Size; + huart->RxXferCount = Size; + + huart->ErrorCode = HAL_UART_ERROR_NONE; + huart->RxState = HAL_UART_STATE_BUSY_RX; + + /* Process Unlocked */ + __HAL_UNLOCK(huart); + + /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */ + SET_BIT(huart->Instance->CR3, USART_CR3_EIE); + + /* Enable the UART Parity Error and Data Register not empty Interrupts */ + SET_BIT(huart->Instance->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Sends an amount of data in non blocking mode. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @param pData: Pointer to data buffer + * @param Size: Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) +{ + uint32_t *tmp; + + /* Check that a Tx process is not already ongoing */ + if(huart->gState == HAL_UART_STATE_READY) + { + if((pData == NULL ) || (Size == 0)) + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(huart); + + huart->pTxBuffPtr = pData; + huart->TxXferSize = Size; + huart->TxXferCount = Size; + + huart->ErrorCode = HAL_UART_ERROR_NONE; + huart->gState = HAL_UART_STATE_BUSY_TX; + + /* Set the UART DMA transfer complete callback */ + huart->hdmatx->XferCpltCallback = UART_DMATransmitCplt; + + /* Set the UART DMA Half transfer complete callback */ + huart->hdmatx->XferHalfCpltCallback = UART_DMATxHalfCplt; + + /* Set the DMA error callback */ + huart->hdmatx->XferErrorCallback = UART_DMAError; + + /* Set the DMA abort callback */ + huart->hdmatx->XferAbortCallback = NULL; + + /* Enable the UART transmit DMA Stream */ + tmp = (uint32_t*)&pData; + HAL_DMA_Start_IT(huart->hdmatx, *(uint32_t*)tmp, (uint32_t)&huart->Instance->DR, Size); + + /* Clear the TC flag in the SR register by writing 0 to it */ + __HAL_UART_CLEAR_FLAG(huart, UART_FLAG_TC); + + /* Process Unlocked */ + __HAL_UNLOCK(huart); + + /* Enable the DMA transfer for transmit request by setting the DMAT bit + in the UART CR3 register */ + SET_BIT(huart->Instance->CR3, USART_CR3_DMAT); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Receives an amount of data in non blocking mode. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @param pData: Pointer to data buffer + * @param Size: Amount of data to be received + * @note When the UART parity is enabled (PCE = 1) the data received contain the parity bit. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) +{ + uint32_t *tmp; + + /* Check that a Rx process is not already ongoing */ + if(huart->RxState == HAL_UART_STATE_READY) + { + if((pData == NULL ) || (Size == 0)) + { + return HAL_ERROR; + } + + /* Process Locked */ + __HAL_LOCK(huart); + + huart->pRxBuffPtr = pData; + huart->RxXferSize = Size; + + huart->ErrorCode = HAL_UART_ERROR_NONE; + huart->RxState = HAL_UART_STATE_BUSY_RX; + + /* Set the UART DMA transfer complete callback */ + huart->hdmarx->XferCpltCallback = UART_DMAReceiveCplt; + + /* Set the UART DMA Half transfer complete callback */ + huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt; + + /* Set the DMA error callback */ + huart->hdmarx->XferErrorCallback = UART_DMAError; + + /* Set the DMA abort callback */ + huart->hdmarx->XferAbortCallback = NULL; + + /* Enable the DMA Stream */ + tmp = (uint32_t*)&pData; + HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t*)tmp, Size); + + /* Clear the Overrun flag just before enabling the DMA Rx request: can be mandatory for the second transfer */ + __HAL_UART_CLEAR_OREFLAG(huart); + + /* Process Unlocked */ + __HAL_UNLOCK(huart); + + /* Enable the UART Parity Error Interrupt */ + SET_BIT(huart->Instance->CR1, USART_CR1_PEIE); + + /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */ + SET_BIT(huart->Instance->CR3, USART_CR3_EIE); + + /* Enable the DMA transfer for the receiver request by setting the DMAR bit + in the UART CR3 register */ + SET_BIT(huart->Instance->CR3, USART_CR3_DMAR); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Pauses the DMA Transfer. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_UART_DMAPause(UART_HandleTypeDef *huart) +{ + uint32_t dmarequest = 0x00U; + + /* Process Locked */ + __HAL_LOCK(huart); + dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAT); + if((huart->gState == HAL_UART_STATE_BUSY_TX) && dmarequest) + { + /* Disable the UART DMA Tx request */ + CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT); + } + dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR); + if((huart->RxState == HAL_UART_STATE_BUSY_RX) && dmarequest) + { + /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */ + CLEAR_BIT(huart->Instance->CR1, USART_CR1_PEIE); + CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE); + + /* Disable the UART DMA Rx request */ + CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR); + } + + /* Process Unlocked */ + __HAL_UNLOCK(huart); + + return HAL_OK; +} + +/** + * @brief Resumes the DMA Transfer. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_UART_DMAResume(UART_HandleTypeDef *huart) +{ + /* Process Locked */ + __HAL_LOCK(huart); + + if(huart->gState == HAL_UART_STATE_BUSY_TX) + { + /* Enable the UART DMA Tx request */ + SET_BIT(huart->Instance->CR3, USART_CR3_DMAT); + } + if(huart->RxState == HAL_UART_STATE_BUSY_RX) + { + /* Clear the Overrun flag before resuming the Rx transfer*/ + __HAL_UART_CLEAR_OREFLAG(huart); + + /* Reenable PE and ERR (Frame error, noise error, overrun error) interrupts */ + SET_BIT(huart->Instance->CR1, USART_CR1_PEIE); + SET_BIT(huart->Instance->CR3, USART_CR3_EIE); + + /* Enable the UART DMA Rx request */ + SET_BIT(huart->Instance->CR3, USART_CR3_DMAR); + } + + /* Process Unlocked */ + __HAL_UNLOCK(huart); + + return HAL_OK; +} + +/** + * @brief Stops the DMA Transfer. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart) +{ + uint32_t dmarequest = 0x00U; + /* The Lock is not implemented on this API to allow the user application + to call the HAL UART API under callbacks HAL_UART_TxCpltCallback() / HAL_UART_RxCpltCallback(): + when calling HAL_DMA_Abort() API the DMA TX/RX Transfer complete interrupt is generated + and the correspond call back is executed HAL_UART_TxCpltCallback() / HAL_UART_RxCpltCallback() + */ + + /* Stop UART DMA Tx request if ongoing */ + dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAT); + if((huart->gState == HAL_UART_STATE_BUSY_TX) && dmarequest) + { + CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT); + + /* Abort the UART DMA Tx channel */ + if(huart->hdmatx != NULL) + { + HAL_DMA_Abort(huart->hdmatx); + } + UART_EndTxTransfer(huart); + } + + /* Stop UART DMA Rx request if ongoing */ + dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR); + if((huart->RxState == HAL_UART_STATE_BUSY_RX) && dmarequest) + { + CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR); + + /* Abort the UART DMA Rx channel */ + if(huart->hdmarx != NULL) + { + HAL_DMA_Abort(huart->hdmarx); + } + UART_EndRxTransfer(huart); + } + + return HAL_OK; +} + +/** + * @brief Abort ongoing transfers (blocking mode). + * @param huart UART handle. + * @note This procedure could be used for aborting any ongoing transfer started in Interrupt or DMA mode. + * This procedure performs following operations : + * - Disable PPP Interrupts + * - Disable the DMA transfer in the peripheral register (if enabled) + * - Abort DMA transfer by calling HAL_DMA_Abort (in case of transfer in DMA mode) + * - Set handle State to READY + * @note This procedure is executed in blocking mode : when exiting function, Abort is considered as completed. + * @retval HAL status +*/ +HAL_StatusTypeDef HAL_UART_Abort(UART_HandleTypeDef *huart) +{ + /* Disable TXEIE, TCIE, RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */ + CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR1_TXEIE | USART_CR1_TCIE)); + CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE); + + /* Disable the UART DMA Tx request if enabled */ + if(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAT)) + { + CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT); + + /* Abort the UART DMA Tx channel: use blocking DMA Abort API (no callback) */ + if(huart->hdmatx != NULL) + { + /* Set the UART DMA Abort callback to Null. + No call back execution at end of DMA abort procedure */ + huart->hdmatx->XferAbortCallback = NULL; + + HAL_DMA_Abort(huart->hdmatx); + } + } + + /* Disable the UART DMA Rx request if enabled */ + if(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)) + { + CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR); + + /* Abort the UART DMA Rx channel: use blocking DMA Abort API (no callback) */ + if(huart->hdmarx != NULL) + { + /* Set the UART DMA Abort callback to Null. + No call back execution at end of DMA abort procedure */ + huart->hdmarx->XferAbortCallback = NULL; + + HAL_DMA_Abort(huart->hdmarx); + } + } + + /* Reset Tx and Rx transfer counters */ + huart->TxXferCount = 0x00U; + huart->RxXferCount = 0x00U; + + /* Reset ErrorCode */ + huart->ErrorCode = HAL_UART_ERROR_NONE; + + /* Restore huart->RxState and huart->gState to Ready */ + huart->RxState = HAL_UART_STATE_READY; + huart->gState = HAL_UART_STATE_READY; + + return HAL_OK; +} + +/** + * @brief Abort ongoing Transmit transfer (blocking mode). + * @param huart UART handle. + * @note This procedure could be used for aborting any ongoing transfer started in Interrupt or DMA mode. + * This procedure performs following operations : + * - Disable PPP Interrupts + * - Disable the DMA transfer in the peripheral register (if enabled) + * - Abort DMA transfer by calling HAL_DMA_Abort (in case of transfer in DMA mode) + * - Set handle State to READY + * @note This procedure is executed in blocking mode : when exiting function, Abort is considered as completed. + * @retval HAL status +*/ +HAL_StatusTypeDef HAL_UART_AbortTransmit(UART_HandleTypeDef *huart) +{ + /* Disable TXEIE and TCIE interrupts */ + CLEAR_BIT(huart->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE)); + + /* Disable the UART DMA Tx request if enabled */ + if(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAT)) + { + CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT); + + /* Abort the UART DMA Tx channel : use blocking DMA Abort API (no callback) */ + if(huart->hdmatx != NULL) + { + /* Set the UART DMA Abort callback to Null. + No call back execution at end of DMA abort procedure */ + huart->hdmatx->XferAbortCallback = NULL; + + HAL_DMA_Abort(huart->hdmatx); + } + } + + /* Reset Tx transfer counter */ + huart->TxXferCount = 0x00U; + + /* Restore huart->gState to Ready */ + huart->gState = HAL_UART_STATE_READY; + + return HAL_OK; +} + +/** + * @brief Abort ongoing Receive transfer (blocking mode). + * @param huart UART handle. + * @note This procedure could be used for aborting any ongoing transfer started in Interrupt or DMA mode. + * This procedure performs following operations : + * - Disable PPP Interrupts + * - Disable the DMA transfer in the peripheral register (if enabled) + * - Abort DMA transfer by calling HAL_DMA_Abort (in case of transfer in DMA mode) + * - Set handle State to READY + * @note This procedure is executed in blocking mode : when exiting function, Abort is considered as completed. + * @retval HAL status +*/ +HAL_StatusTypeDef HAL_UART_AbortReceive(UART_HandleTypeDef *huart) +{ + /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */ + CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE)); + CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE); + + /* Disable the UART DMA Rx request if enabled */ + if(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)) + { + CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR); + + /* Abort the UART DMA Rx channel : use blocking DMA Abort API (no callback) */ + if(huart->hdmarx != NULL) + { + /* Set the UART DMA Abort callback to Null. + No call back execution at end of DMA abort procedure */ + huart->hdmarx->XferAbortCallback = NULL; + + HAL_DMA_Abort(huart->hdmarx); + } + } + + /* Reset Rx transfer counter */ + huart->RxXferCount = 0x00U; + + /* Restore huart->RxState to Ready */ + huart->RxState = HAL_UART_STATE_READY; + + return HAL_OK; +} + +/** + * @brief Abort ongoing transfers (Interrupt mode). + * @param huart UART handle. + * @note This procedure could be used for aborting any ongoing transfer started in Interrupt or DMA mode. + * This procedure performs following operations : + * - Disable PPP Interrupts + * - Disable the DMA transfer in the peripheral register (if enabled) + * - Abort DMA transfer by calling HAL_DMA_Abort_IT (in case of transfer in DMA mode) + * - Set handle State to READY + * - At abort completion, call user abort complete callback + * @note This procedure is executed in Interrupt mode, meaning that abort procedure could be + * considered as completed only when user abort complete callback is executed (not when exiting function). + * @retval HAL status +*/ +HAL_StatusTypeDef HAL_UART_Abort_IT(UART_HandleTypeDef *huart) +{ + uint32_t AbortCplt = 0x01U; + + /* Disable TXEIE, TCIE, RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */ + CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR1_TXEIE | USART_CR1_TCIE)); + CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE); + + /* If DMA Tx and/or DMA Rx Handles are associated to UART Handle, DMA Abort complete callbacks should be initialised + before any call to DMA Abort functions */ + /* DMA Tx Handle is valid */ + if(huart->hdmatx != NULL) + { + /* Set DMA Abort Complete callback if UART DMA Tx request if enabled. + Otherwise, set it to NULL */ + if(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAT)) + { + huart->hdmatx->XferAbortCallback = UART_DMATxAbortCallback; + } + else + { + huart->hdmatx->XferAbortCallback = NULL; + } + } + /* DMA Rx Handle is valid */ + if(huart->hdmarx != NULL) + { + /* Set DMA Abort Complete callback if UART DMA Rx request if enabled. + Otherwise, set it to NULL */ + if(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)) + { + huart->hdmarx->XferAbortCallback = UART_DMARxAbortCallback; + } + else + { + huart->hdmarx->XferAbortCallback = NULL; + } + } + + /* Disable the UART DMA Tx request if enabled */ + if(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAT)) + { + /* Disable DMA Tx at UART level */ + CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT); + + /* Abort the UART DMA Tx channel : use non blocking DMA Abort API (callback) */ + if(huart->hdmatx != NULL) + { + /* UART Tx DMA Abort callback has already been initialised : + will lead to call HAL_UART_AbortCpltCallback() at end of DMA abort procedure */ + + /* Abort DMA TX */ + if(HAL_DMA_Abort_IT(huart->hdmatx) != HAL_OK) + { + huart->hdmatx->XferAbortCallback = NULL; + } + else + { + AbortCplt = 0x00U; + } + } + } + + /* Disable the UART DMA Rx request if enabled */ + if(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)) + { + CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR); + + /* Abort the UART DMA Rx channel : use non blocking DMA Abort API (callback) */ + if(huart->hdmarx != NULL) + { + /* UART Rx DMA Abort callback has already been initialised : + will lead to call HAL_UART_AbortCpltCallback() at end of DMA abort procedure */ + + /* Abort DMA RX */ + if(HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK) + { + huart->hdmarx->XferAbortCallback = NULL; + AbortCplt = 0x01U; + } + else + { + AbortCplt = 0x00U; + } + } + } + + /* if no DMA abort complete callback execution is required => call user Abort Complete callback */ + if(AbortCplt == 0x01U) + { + /* Reset Tx and Rx transfer counters */ + huart->TxXferCount = 0x00U; + huart->RxXferCount = 0x00U; + + /* Reset ErrorCode */ + huart->ErrorCode = HAL_UART_ERROR_NONE; + + /* Restore huart->gState and huart->RxState to Ready */ + huart->gState = HAL_UART_STATE_READY; + huart->RxState = HAL_UART_STATE_READY; + + /* As no DMA to be aborted, call directly user Abort complete callback */ + HAL_UART_AbortCpltCallback(huart); + } + + return HAL_OK; +} + +/** + * @brief Abort ongoing Transmit transfer (Interrupt mode). + * @param huart UART handle. + * @note This procedure could be used for aborting any ongoing transfer started in Interrupt or DMA mode. + * This procedure performs following operations : + * - Disable PPP Interrupts + * - Disable the DMA transfer in the peripheral register (if enabled) + * - Abort DMA transfer by calling HAL_DMA_Abort_IT (in case of transfer in DMA mode) + * - Set handle State to READY + * - At abort completion, call user abort complete callback + * @note This procedure is executed in Interrupt mode, meaning that abort procedure could be + * considered as completed only when user abort complete callback is executed (not when exiting function). + * @retval HAL status +*/ +HAL_StatusTypeDef HAL_UART_AbortTransmit_IT(UART_HandleTypeDef *huart) +{ + /* Disable TXEIE and TCIE interrupts */ + CLEAR_BIT(huart->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE)); + + /* Disable the UART DMA Tx request if enabled */ + if(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAT)) + { + CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT); + + /* Abort the UART DMA Tx channel : use blocking DMA Abort API (no callback) */ + if(huart->hdmatx != NULL) + { + /* Set the UART DMA Abort callback : + will lead to call HAL_UART_AbortCpltCallback() at end of DMA abort procedure */ + huart->hdmatx->XferAbortCallback = UART_DMATxOnlyAbortCallback; + + /* Abort DMA TX */ + if(HAL_DMA_Abort_IT(huart->hdmatx) != HAL_OK) + { + /* Call Directly huart->hdmatx->XferAbortCallback function in case of error */ + huart->hdmatx->XferAbortCallback(huart->hdmatx); + } + } + else + { + /* Reset Tx transfer counter */ + huart->TxXferCount = 0x00U; + + /* Restore huart->gState to Ready */ + huart->gState = HAL_UART_STATE_READY; + + /* As no DMA to be aborted, call directly user Abort complete callback */ + HAL_UART_AbortTransmitCpltCallback(huart); + } + } + else + { + /* Reset Tx transfer counter */ + huart->TxXferCount = 0x00U; + + /* Restore huart->gState to Ready */ + huart->gState = HAL_UART_STATE_READY; + + /* As no DMA to be aborted, call directly user Abort complete callback */ + HAL_UART_AbortTransmitCpltCallback(huart); + } + + return HAL_OK; +} + +/** + * @brief Abort ongoing Receive transfer (Interrupt mode). + * @param huart UART handle. + * @note This procedure could be used for aborting any ongoing transfer started in Interrupt or DMA mode. + * This procedure performs following operations : + * - Disable PPP Interrupts + * - Disable the DMA transfer in the peripheral register (if enabled) + * - Abort DMA transfer by calling HAL_DMA_Abort_IT (in case of transfer in DMA mode) + * - Set handle State to READY + * - At abort completion, call user abort complete callback + * @note This procedure is executed in Interrupt mode, meaning that abort procedure could be + * considered as completed only when user abort complete callback is executed (not when exiting function). + * @retval HAL status +*/ +HAL_StatusTypeDef HAL_UART_AbortReceive_IT(UART_HandleTypeDef *huart) +{ + /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */ + CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE)); + CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE); + + /* Disable the UART DMA Rx request if enabled */ + if(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)) + { + CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR); + + /* Abort the UART DMA Rx channel : use blocking DMA Abort API (no callback) */ + if(huart->hdmarx != NULL) + { + /* Set the UART DMA Abort callback : + will lead to call HAL_UART_AbortCpltCallback() at end of DMA abort procedure */ + huart->hdmarx->XferAbortCallback = UART_DMARxOnlyAbortCallback; + + /* Abort DMA RX */ + if(HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK) + { + /* Call Directly huart->hdmarx->XferAbortCallback function in case of error */ + huart->hdmarx->XferAbortCallback(huart->hdmarx); + } + } + else + { + /* Reset Rx transfer counter */ + huart->RxXferCount = 0x00U; + + /* Restore huart->RxState to Ready */ + huart->RxState = HAL_UART_STATE_READY; + + /* As no DMA to be aborted, call directly user Abort complete callback */ + HAL_UART_AbortReceiveCpltCallback(huart); + } + } + else + { + /* Reset Rx transfer counter */ + huart->RxXferCount = 0x00U; + + /* Restore huart->RxState to Ready */ + huart->RxState = HAL_UART_STATE_READY; + + /* As no DMA to be aborted, call directly user Abort complete callback */ + HAL_UART_AbortReceiveCpltCallback(huart); + } + + return HAL_OK; +} + +/** + * @brief This function handles UART interrupt request. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval None + */ +void HAL_UART_IRQHandler(UART_HandleTypeDef *huart) +{ + uint32_t isrflags = READ_REG(huart->Instance->SR); + uint32_t cr1its = READ_REG(huart->Instance->CR1); + uint32_t cr3its = READ_REG(huart->Instance->CR3); + uint32_t errorflags = 0x00U; + uint32_t dmarequest = 0x00U; + + /* If no error occurs */ + errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE)); + if(errorflags == RESET) + { + /* UART in mode Receiver -------------------------------------------------*/ + if(((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET)) + { + UART_Receive_IT(huart); + return; + } + } + + /* If some errors occur */ + if((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET))) + { + /* UART parity error interrupt occurred ----------------------------------*/ + if(((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET)) + { + huart->ErrorCode |= HAL_UART_ERROR_PE; + } + + /* UART noise error interrupt occurred -----------------------------------*/ + if(((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET)) + { + huart->ErrorCode |= HAL_UART_ERROR_NE; + } + + /* UART frame error interrupt occurred -----------------------------------*/ + if(((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET)) + { + huart->ErrorCode |= HAL_UART_ERROR_FE; + } + + /* UART Over-Run interrupt occurred --------------------------------------*/ + if(((isrflags & USART_SR_ORE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET)) + { + huart->ErrorCode |= HAL_UART_ERROR_ORE; + } + + /* Call UART Error Call back function if need be --------------------------*/ + if(huart->ErrorCode != HAL_UART_ERROR_NONE) + { + /* UART in mode Receiver -----------------------------------------------*/ + if(((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET)) + { + UART_Receive_IT(huart); + } + + /* If Overrun error occurs, or if any error occurs in DMA mode reception, + consider error as blocking */ + dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR); + if(((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) || dmarequest) + { + /* Blocking error : transfer is aborted + Set the UART state ready to be able to start again the process, + Disable Rx Interrupts, and disable Rx DMA request, if ongoing */ + UART_EndRxTransfer(huart); + + /* Disable the UART DMA Rx request if enabled */ + if(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)) + { + CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR); + + /* Abort the UART DMA Rx channel */ + if(huart->hdmarx != NULL) + { + /* Set the UART DMA Abort callback : + will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */ + huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError; + if(HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK) + { + /* Call Directly XferAbortCallback function in case of error */ + huart->hdmarx->XferAbortCallback(huart->hdmarx); + } + } + else + { + /* Call user error callback */ + HAL_UART_ErrorCallback(huart); + } + } + else + { + /* Call user error callback */ + HAL_UART_ErrorCallback(huart); + } + } + else + { + /* Non Blocking error : transfer could go on. + Error is notified to user through user error callback */ + HAL_UART_ErrorCallback(huart); + huart->ErrorCode = HAL_UART_ERROR_NONE; + } + } + return; + } /* End if some error occurs */ + + /* UART in mode Transmitter ------------------------------------------------*/ + if(((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET)) + { + UART_Transmit_IT(huart); + return; + } + + /* UART in mode Transmitter end --------------------------------------------*/ + if(((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET)) + { + UART_EndTransmit_IT(huart); + return; + } +} + +/** + * @brief Tx Transfer completed callbacks. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval None + */ + __weak void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(huart); + /* NOTE: This function Should not be modified, when the callback is needed, + the HAL_UART_TxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief Tx Half Transfer completed callbacks. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval None + */ + __weak void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(huart); + /* NOTE: This function Should not be modified, when the callback is needed, + the HAL_UART_TxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief Rx Transfer completed callbacks. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval None + */ +__weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(huart); + /* NOTE: This function Should not be modified, when the callback is needed, + the HAL_UART_TxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief Rx Half Transfer completed callbacks. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval None + */ +__weak void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(huart); + /* NOTE: This function Should not be modified, when the callback is needed, + the HAL_UART_TxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief UART error callbacks. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval None + */ + __weak void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(huart); + /* NOTE: This function Should not be modified, when the callback is needed, + the HAL_UART_ErrorCallback could be implemented in the user file + */ +} + +/** + * @brief UART Abort Complete callback. + * @param huart UART handle. + * @retval None + */ +__weak void HAL_UART_AbortCpltCallback (UART_HandleTypeDef *huart) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(huart); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_UART_AbortCpltCallback can be implemented in the user file. + */ +} +/** + * @brief UART Abort Complete callback. + * @param huart UART handle. + * @retval None + */ +__weak void HAL_UART_AbortTransmitCpltCallback (UART_HandleTypeDef *huart) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(huart); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_UART_AbortTransmitCpltCallback can be implemented in the user file. + */ +} + +/** + * @brief UART Abort Receive Complete callback. + * @param huart UART handle. + * @retval None + */ +__weak void HAL_UART_AbortReceiveCpltCallback (UART_HandleTypeDef *huart) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(huart); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_UART_AbortReceiveCpltCallback can be implemented in the user file. + */ +} + +/** + * @} + */ + +/** @defgroup UART_Exported_Functions_Group3 Peripheral Control functions + * @brief UART control functions + * +@verbatim + ============================================================================== + ##### Peripheral Control functions ##### + ============================================================================== + [..] + This subsection provides a set of functions allowing to control the UART: + (+) HAL_LIN_SendBreak() API can be helpful to transmit the break character. + (+) HAL_MultiProcessor_EnterMuteMode() API can be helpful to enter the UART in mute mode. + (+) HAL_MultiProcessor_ExitMuteMode() API can be helpful to exit the UART mute mode by software. + +@endverbatim + * @{ + */ + +/** + * @brief Transmits break characters. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_LIN_SendBreak(UART_HandleTypeDef *huart) +{ + /* Check the parameters */ + assert_param(IS_UART_INSTANCE(huart->Instance)); + + /* Process Locked */ + __HAL_LOCK(huart); + + huart->gState = HAL_UART_STATE_BUSY; + + /* Send break characters */ + SET_BIT(huart->Instance->CR1, USART_CR1_SBK); + + huart->gState = HAL_UART_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(huart); + + return HAL_OK; +} + +/** + * @brief Enters the UART in mute mode. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_MultiProcessor_EnterMuteMode(UART_HandleTypeDef *huart) +{ + /* Check the parameters */ + assert_param(IS_UART_INSTANCE(huart->Instance)); + + /* Process Locked */ + __HAL_LOCK(huart); + + huart->gState = HAL_UART_STATE_BUSY; + + /* Enable the USART mute mode by setting the RWU bit in the CR1 register */ + SET_BIT(huart->Instance->CR1, USART_CR1_RWU); + + huart->gState = HAL_UART_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(huart); + + return HAL_OK; +} + +/** + * @brief Exits the UART mute mode: wake up software. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_MultiProcessor_ExitMuteMode(UART_HandleTypeDef *huart) +{ + /* Check the parameters */ + assert_param(IS_UART_INSTANCE(huart->Instance)); + + /* Process Locked */ + __HAL_LOCK(huart); + + huart->gState = HAL_UART_STATE_BUSY; + + /* Disable the USART mute mode by clearing the RWU bit in the CR1 register */ + CLEAR_BIT(huart->Instance->CR1, USART_CR1_RWU); + + huart->gState = HAL_UART_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(huart); + + return HAL_OK; +} + +/** + * @brief Enables the UART transmitter and disables the UART receiver. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_HalfDuplex_EnableTransmitter(UART_HandleTypeDef *huart) +{ + uint32_t tmpreg = 0x00U; + + /* Process Locked */ + __HAL_LOCK(huart); + + huart->gState = HAL_UART_STATE_BUSY; + + /*-------------------------- USART CR1 Configuration -----------------------*/ + tmpreg = huart->Instance->CR1; + + /* Clear TE and RE bits */ + tmpreg &= (uint32_t)~((uint32_t)(USART_CR1_TE | USART_CR1_RE)); + + /* Enable the USART's transmit interface by setting the TE bit in the USART CR1 register */ + tmpreg |= (uint32_t)USART_CR1_TE; + + /* Write to USART CR1 */ + WRITE_REG(huart->Instance->CR1, (uint32_t)tmpreg); + + huart->gState = HAL_UART_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(huart); + + return HAL_OK; +} + +/** + * @brief Enables the UART receiver and disables the UART transmitter. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_HalfDuplex_EnableReceiver(UART_HandleTypeDef *huart) +{ + uint32_t tmpreg = 0x00U; + + /* Process Locked */ + __HAL_LOCK(huart); + + huart->gState = HAL_UART_STATE_BUSY; + + /*-------------------------- USART CR1 Configuration -----------------------*/ + tmpreg = huart->Instance->CR1; + + /* Clear TE and RE bits */ + tmpreg &= (uint32_t)~((uint32_t)(USART_CR1_TE | USART_CR1_RE)); + + /* Enable the USART's receive interface by setting the RE bit in the USART CR1 register */ + tmpreg |= (uint32_t)USART_CR1_RE; + + /* Write to USART CR1 */ + WRITE_REG(huart->Instance->CR1, (uint32_t)tmpreg); + + huart->gState = HAL_UART_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(huart); + + return HAL_OK; +} + +/** + * @} + */ + +/** @defgroup UART_Exported_Functions_Group4 Peripheral State and Errors functions + * @brief UART State and Errors functions + * +@verbatim + ============================================================================== + ##### Peripheral State and Errors functions ##### + ============================================================================== + [..] + This subsection provides a set of functions allowing to return the State of + UART communication process, return Peripheral Errors occurred during communication + process + (+) HAL_UART_GetState() API can be helpful to check in run-time the state of the UART peripheral. + (+) HAL_UART_GetError() check in run-time errors that could be occurred during communication. + +@endverbatim + * @{ + */ + +/** + * @brief Returns the UART state. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval HAL state + */ +HAL_UART_StateTypeDef HAL_UART_GetState(UART_HandleTypeDef *huart) +{ + uint32_t temp1= 0x00U, temp2 = 0x00U; + temp1 = huart->gState; + temp2 = huart->RxState; + + return (HAL_UART_StateTypeDef)(temp1 | temp2); +} + +/** + * @brief Return the UART error code + * @param huart : pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART. + * @retval UART Error Code + */ +uint32_t HAL_UART_GetError(UART_HandleTypeDef *huart) +{ + return huart->ErrorCode; +} + +/** + * @} + */ + +/** + * @brief DMA UART transmit process complete callback. + * @param hdma: DMA handle + * @retval None + */ +static void UART_DMATransmitCplt(DMA_HandleTypeDef *hdma) +{ + UART_HandleTypeDef* huart = ( UART_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent; + /* DMA Normal mode*/ + if((hdma->Instance->CR & DMA_SxCR_CIRC) == 0U) + { + huart->TxXferCount = 0U; + + /* Disable the DMA transfer for transmit request by setting the DMAT bit + in the UART CR3 register */ + CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT); + + /* Enable the UART Transmit Complete Interrupt */ + SET_BIT(huart->Instance->CR1, USART_CR1_TCIE); + + } + /* DMA Circular mode */ + else + { + HAL_UART_TxCpltCallback(huart); + } +} + +/** + * @brief DMA UART transmit process half complete callback + * @param hdma: pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +static void UART_DMATxHalfCplt(DMA_HandleTypeDef *hdma) +{ + UART_HandleTypeDef* huart = (UART_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent; + + HAL_UART_TxHalfCpltCallback(huart); +} + +/** + * @brief DMA UART receive process complete callback. + * @param hdma: DMA handle + * @retval None + */ +static void UART_DMAReceiveCplt(DMA_HandleTypeDef *hdma) +{ + UART_HandleTypeDef* huart = ( UART_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent; + /* DMA Normal mode*/ + if((hdma->Instance->CR & DMA_SxCR_CIRC) == 0U) + { + huart->RxXferCount = 0U; + + /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */ + CLEAR_BIT(huart->Instance->CR1, USART_CR1_PEIE); + CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE); + + /* Disable the DMA transfer for the receiver request by setting the DMAR bit + in the UART CR3 register */ + CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR); + + /* At end of Rx process, restore huart->RxState to Ready */ + huart->RxState = HAL_UART_STATE_READY; + } + HAL_UART_RxCpltCallback(huart); +} + +/** + * @brief DMA UART receive process half complete callback + * @param hdma: pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +static void UART_DMARxHalfCplt(DMA_HandleTypeDef *hdma) +{ + UART_HandleTypeDef* huart = (UART_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent; + + HAL_UART_RxHalfCpltCallback(huart); +} + +/** + * @brief DMA UART communication error callback. + * @param hdma: DMA handle + * @retval None + */ +static void UART_DMAError(DMA_HandleTypeDef *hdma) +{ + uint32_t dmarequest = 0x00U; + UART_HandleTypeDef* huart = ( UART_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent; + + /* Stop UART DMA Tx request if ongoing */ + dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAT); + if((huart->gState == HAL_UART_STATE_BUSY_TX) && dmarequest) + { + huart->TxXferCount = 0U; + UART_EndTxTransfer(huart); + } + + /* Stop UART DMA Rx request if ongoing */ + dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR); + if((huart->RxState == HAL_UART_STATE_BUSY_RX) && dmarequest) + { + huart->RxXferCount = 0U; + UART_EndRxTransfer(huart); + } + + huart->ErrorCode |= HAL_UART_ERROR_DMA; + HAL_UART_ErrorCallback(huart); +} + +/** + * @brief This function handles UART Communication Timeout. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @param Flag: specifies the UART flag to check. + * @param Status: The new Flag status (SET or RESET). + * @param Tickstart Tick start value + * @param Timeout: Timeout duration + * @retval HAL status + */ +static HAL_StatusTypeDef UART_WaitOnFlagUntilTimeout(UART_HandleTypeDef *huart, uint32_t Flag, FlagStatus Status, uint32_t Tickstart, uint32_t Timeout) +{ + /* Wait until flag is set */ + while((__HAL_UART_GET_FLAG(huart, Flag) ? SET : RESET) == Status) + { + /* Check for the Timeout */ + if(Timeout != HAL_MAX_DELAY) + { + if((Timeout == 0U)||((HAL_GetTick() - Tickstart ) > Timeout)) + { + /* Disable TXE, RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts for the interrupt process */ + CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR1_TXEIE)); + CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE); + + huart->gState = HAL_UART_STATE_READY; + huart->RxState = HAL_UART_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(huart); + + return HAL_TIMEOUT; + } + } + } + + return HAL_OK; +} + +/** + * @brief End ongoing Tx transfer on UART peripheral (following error detection or Transmit completion). + * @param huart: UART handle. + * @retval None + */ +static void UART_EndTxTransfer(UART_HandleTypeDef *huart) +{ + /* Disable TXEIE and TCIE interrupts */ + CLEAR_BIT(huart->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE)); + + /* At end of Tx process, restore huart->gState to Ready */ + huart->gState = HAL_UART_STATE_READY; +} + +/** + * @brief End ongoing Rx transfer on UART peripheral (following error detection or Reception completion). + * @param huart: UART handle. + * @retval None + */ +static void UART_EndRxTransfer(UART_HandleTypeDef *huart) +{ + /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */ + CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE)); + CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE); + + /* At end of Rx process, restore huart->RxState to Ready */ + huart->RxState = HAL_UART_STATE_READY; +} + +/** + * @brief DMA UART communication abort callback, when initiated by HAL services on Error + * (To be called at end of DMA Abort procedure following error occurrence). + * @param hdma DMA handle. + * @retval None + */ +static void UART_DMAAbortOnError(DMA_HandleTypeDef *hdma) +{ + UART_HandleTypeDef* huart = ( UART_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent; + huart->RxXferCount = 0U; + huart->TxXferCount = 0U; + + HAL_UART_ErrorCallback(huart); +} + +/** + * @brief DMA UART Tx communication abort callback, when initiated by user + * (To be called at end of DMA Tx Abort procedure following user abort request). + * @note When this callback is executed, User Abort complete call back is called only if no + * Abort still ongoing for Rx DMA Handle. + * @param hdma DMA handle. + * @retval None + */ +static void UART_DMATxAbortCallback(DMA_HandleTypeDef *hdma) +{ + UART_HandleTypeDef* huart = ( UART_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent; + + huart->hdmatx->XferAbortCallback = NULL; + + /* Check if an Abort process is still ongoing */ + if(huart->hdmarx != NULL) + { + if(huart->hdmarx->XferAbortCallback != NULL) + { + return; + } + } + + /* No Abort process still ongoing : All DMA channels are aborted, call user Abort Complete callback */ + huart->TxXferCount = 0x00U; + huart->RxXferCount = 0x00U; + + /* Reset ErrorCode */ + huart->ErrorCode = HAL_UART_ERROR_NONE; + + /* Restore huart->gState and huart->RxState to Ready */ + huart->gState = HAL_UART_STATE_READY; + huart->RxState = HAL_UART_STATE_READY; + + /* Call user Abort complete callback */ + HAL_UART_AbortCpltCallback(huart); +} + +/** + * @brief DMA UART Rx communication abort callback, when initiated by user + * (To be called at end of DMA Rx Abort procedure following user abort request). + * @note When this callback is executed, User Abort complete call back is called only if no + * Abort still ongoing for Tx DMA Handle. + * @param hdma DMA handle. + * @retval None + */ +static void UART_DMARxAbortCallback(DMA_HandleTypeDef *hdma) +{ + UART_HandleTypeDef* huart = ( UART_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent; + + huart->hdmarx->XferAbortCallback = NULL; + + /* Check if an Abort process is still ongoing */ + if(huart->hdmatx != NULL) + { + if(huart->hdmatx->XferAbortCallback != NULL) + { + return; + } + } + + /* No Abort process still ongoing : All DMA channels are aborted, call user Abort Complete callback */ + huart->TxXferCount = 0x00U; + huart->RxXferCount = 0x00U; + + /* Reset ErrorCode */ + huart->ErrorCode = HAL_UART_ERROR_NONE; + + /* Restore huart->gState and huart->RxState to Ready */ + huart->gState = HAL_UART_STATE_READY; + huart->RxState = HAL_UART_STATE_READY; + + /* Call user Abort complete callback */ + HAL_UART_AbortCpltCallback(huart); +} + +/** + * @brief DMA UART Tx communication abort callback, when initiated by user by a call to + * HAL_UART_AbortTransmit_IT API (Abort only Tx transfer) + * (This callback is executed at end of DMA Tx Abort procedure following user abort request, + * and leads to user Tx Abort Complete callback execution). + * @param hdma DMA handle. + * @retval None + */ +static void UART_DMATxOnlyAbortCallback(DMA_HandleTypeDef *hdma) +{ + UART_HandleTypeDef* huart = ( UART_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent; + + huart->TxXferCount = 0x00U; + + /* Restore huart->gState to Ready */ + huart->gState = HAL_UART_STATE_READY; + + /* Call user Abort complete callback */ + HAL_UART_AbortTransmitCpltCallback(huart); +} + +/** + * @brief DMA UART Rx communication abort callback, when initiated by user by a call to + * HAL_UART_AbortReceive_IT API (Abort only Rx transfer) + * (This callback is executed at end of DMA Rx Abort procedure following user abort request, + * and leads to user Rx Abort Complete callback execution). + * @param hdma DMA handle. + * @retval None + */ +static void UART_DMARxOnlyAbortCallback(DMA_HandleTypeDef *hdma) +{ + UART_HandleTypeDef* huart = ( UART_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent; + + huart->RxXferCount = 0x00U; + + /* Restore huart->RxState to Ready */ + huart->RxState = HAL_UART_STATE_READY; + + /* Call user Abort complete callback */ + HAL_UART_AbortReceiveCpltCallback(huart); +} + +/** + * @brief Sends an amount of data in non blocking mode. + * @param huart: Pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval HAL status + */ +static HAL_StatusTypeDef UART_Transmit_IT(UART_HandleTypeDef *huart) +{ + uint16_t* tmp; + + /* Check that a Tx process is ongoing */ + if(huart->gState == HAL_UART_STATE_BUSY_TX) + { + if(huart->Init.WordLength == UART_WORDLENGTH_9B) + { + tmp = (uint16_t*) huart->pTxBuffPtr; + huart->Instance->DR = (uint16_t)(*tmp & (uint16_t)0x01FF); + if(huart->Init.Parity == UART_PARITY_NONE) + { + huart->pTxBuffPtr += 2U; + } + else + { + huart->pTxBuffPtr += 1U; + } + } + else + { + huart->Instance->DR = (uint8_t)(*huart->pTxBuffPtr++ & (uint8_t)0x00FF); + } + + if(--huart->TxXferCount == 0U) + { + /* Disable the UART Transmit Complete Interrupt */ + CLEAR_BIT(huart->Instance->CR1, USART_CR1_TXEIE); + + /* Enable the UART Transmit Complete Interrupt */ + SET_BIT(huart->Instance->CR1, USART_CR1_TCIE); + } + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Wraps up transmission in non blocking mode. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval HAL status + */ +static HAL_StatusTypeDef UART_EndTransmit_IT(UART_HandleTypeDef *huart) +{ + /* Disable the UART Transmit Complete Interrupt */ + CLEAR_BIT(huart->Instance->CR1, USART_CR1_TCIE); + + /* Tx process is ended, restore huart->gState to Ready */ + huart->gState = HAL_UART_STATE_READY; + + HAL_UART_TxCpltCallback(huart); + + return HAL_OK; +} + +/** + * @brief Receives an amount of data in non blocking mode + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval HAL status + */ +static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart) +{ + uint16_t* tmp; + + /* Check that a Rx process is ongoing */ + if(huart->RxState == HAL_UART_STATE_BUSY_RX) + { + if(huart->Init.WordLength == UART_WORDLENGTH_9B) + { + tmp = (uint16_t*) huart->pRxBuffPtr; + if(huart->Init.Parity == UART_PARITY_NONE) + { + *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF); + huart->pRxBuffPtr += 2U; + } + else + { + *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF); + huart->pRxBuffPtr += 1U; + } + } + else + { + if(huart->Init.Parity == UART_PARITY_NONE) + { + *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF); + } + else + { + *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F); + } + } + + if(--huart->RxXferCount == 0U) + { + /* Disable the UART Parity Error Interrupt and RXNE interrupt*/ + CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE)); + + /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */ + CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE); + + /* Rx process is completed, restore huart->RxState to Ready */ + huart->RxState = HAL_UART_STATE_READY; + + HAL_UART_RxCpltCallback(huart); + + return HAL_OK; + } + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Configures the UART peripheral. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval None + */ +static void UART_SetConfig(UART_HandleTypeDef *huart) +{ + uint32_t tmpreg = 0x00U; + + /* Check the parameters */ + assert_param(IS_UART_BAUDRATE(huart->Init.BaudRate)); + assert_param(IS_UART_STOPBITS(huart->Init.StopBits)); + assert_param(IS_UART_PARITY(huart->Init.Parity)); + assert_param(IS_UART_MODE(huart->Init.Mode)); + + /*-------------------------- USART CR2 Configuration -----------------------*/ + tmpreg = huart->Instance->CR2; + + /* Clear STOP[13:12] bits */ + tmpreg &= (uint32_t)~((uint32_t)USART_CR2_STOP); + + /* Configure the UART Stop Bits: Set STOP[13:12] bits according to huart->Init.StopBits value */ + tmpreg |= (uint32_t)huart->Init.StopBits; + + /* Write to USART CR2 */ + WRITE_REG(huart->Instance->CR2, (uint32_t)tmpreg); + + /*-------------------------- USART CR1 Configuration -----------------------*/ + tmpreg = huart->Instance->CR1; + + /* Clear M, PCE, PS, TE and RE bits */ + tmpreg &= (uint32_t)~((uint32_t)(USART_CR1_M | USART_CR1_PCE | USART_CR1_PS | USART_CR1_TE | \ + USART_CR1_RE | USART_CR1_OVER8)); + + /* Configure the UART Word Length, Parity and mode: + Set the M bits according to huart->Init.WordLength value + Set PCE and PS bits according to huart->Init.Parity value + Set TE and RE bits according to huart->Init.Mode value + Set OVER8 bit according to huart->Init.OverSampling value */ + tmpreg |= (uint32_t)huart->Init.WordLength | huart->Init.Parity | huart->Init.Mode | huart->Init.OverSampling; + + /* Write to USART CR1 */ + WRITE_REG(huart->Instance->CR1, (uint32_t)tmpreg); + + /*-------------------------- USART CR3 Configuration -----------------------*/ + tmpreg = huart->Instance->CR3; + + /* Clear CTSE and RTSE bits */ + tmpreg &= (uint32_t)~((uint32_t)(USART_CR3_RTSE | USART_CR3_CTSE)); + + /* Configure the UART HFC: Set CTSE and RTSE bits according to huart->Init.HwFlowCtl value */ + tmpreg |= huart->Init.HwFlowCtl; + + /* Write to USART CR3 */ + WRITE_REG(huart->Instance->CR3, (uint32_t)tmpreg); + + /* Check the Over Sampling */ + if(huart->Init.OverSampling == UART_OVERSAMPLING_8) + { + /*-------------------------- USART BRR Configuration ---------------------*/ +#if defined(USART6) + if((huart->Instance == USART1) || (huart->Instance == USART6)) + { + huart->Instance->BRR = UART_BRR_SAMPLING8(HAL_RCC_GetPCLK2Freq(), huart->Init.BaudRate); + } +#else + if(huart->Instance == USART1) + { + huart->Instance->BRR = UART_BRR_SAMPLING8(HAL_RCC_GetPCLK2Freq(), huart->Init.BaudRate); + } +#endif /* USART6 */ + else + { + huart->Instance->BRR = UART_BRR_SAMPLING8(HAL_RCC_GetPCLK1Freq(), huart->Init.BaudRate); + } + } + else + { + /*-------------------------- USART BRR Configuration ---------------------*/ +#if defined(USART6) + if((huart->Instance == USART1) || (huart->Instance == USART6)) + { + huart->Instance->BRR = UART_BRR_SAMPLING16(HAL_RCC_GetPCLK2Freq(), huart->Init.BaudRate); + } +#else + if(huart->Instance == USART1) + { + huart->Instance->BRR = UART_BRR_SAMPLING16(HAL_RCC_GetPCLK2Freq(), huart->Init.BaudRate); + } +#endif /* USART6 */ + else + { + huart->Instance->BRR = UART_BRR_SAMPLING16(HAL_RCC_GetPCLK1Freq(), huart->Init.BaudRate); + } + } +} + +/** + * @} + */ + +#endif /* HAL_UART_MODULE_ENABLED */ +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/Inc/gpio.h b/Inc/gpio.h index 8a1da672..2046a9b9 100644 --- a/Inc/gpio.h +++ b/Inc/gpio.h @@ -70,6 +70,9 @@ void MX_GPIO_Init(void); /* USER CODE BEGIN Prototypes */ +void SetGPIO12toUART(); +void SetGPIO12toStepDir(); + /* USER CODE END Prototypes */ #ifdef __cplusplus diff --git a/Inc/main.h b/Inc/main.h index a2fdb772..9cb5011d 100644 --- a/Inc/main.h +++ b/Inc/main.h @@ -81,7 +81,6 @@ #define M1_IB_GPIO_Port GPIOC #define GPIO_1_Pin GPIO_PIN_0 #define GPIO_1_GPIO_Port GPIOA -#define GPIO_1_EXTI_IRQn EXTI0_IRQn #define GPIO_2_Pin GPIO_PIN_1 #define GPIO_2_GPIO_Port GPIOA #define GPIO_3_Pin GPIO_PIN_2 diff --git a/Inc/stm32f4xx_hal_conf.h b/Inc/stm32f4xx_hal_conf.h index 6135ec5e..32073570 100644 --- a/Inc/stm32f4xx_hal_conf.h +++ b/Inc/stm32f4xx_hal_conf.h @@ -76,7 +76,7 @@ /* #define HAL_MMC_MODULE_ENABLED */ #define HAL_SPI_MODULE_ENABLED #define HAL_TIM_MODULE_ENABLED -/* #define HAL_UART_MODULE_ENABLED */ +#define HAL_UART_MODULE_ENABLED /* #define HAL_USART_MODULE_ENABLED */ /* #define HAL_IRDA_MODULE_ENABLED */ /* #define HAL_SMARTCARD_MODULE_ENABLED */ diff --git a/Inc/stm32f4xx_it.h b/Inc/stm32f4xx_it.h index 74b19b28..e7b8672f 100644 --- a/Inc/stm32f4xx_it.h +++ b/Inc/stm32f4xx_it.h @@ -52,8 +52,6 @@ void BusFault_Handler(void); void UsageFault_Handler(void); void DebugMon_Handler(void); void SysTick_Handler(void); -void EXTI0_IRQHandler(void); -void EXTI2_IRQHandler(void); void ADC_IRQHandler(void); void OTG_FS_IRQHandler(void); diff --git a/Inc/usart.h b/Inc/usart.h new file mode 100644 index 00000000..808284cd --- /dev/null +++ b/Inc/usart.h @@ -0,0 +1,91 @@ +/** + ****************************************************************************** + * File Name : USART.h + * Description : This file provides code for the configuration + * of the USART instances. + ****************************************************************************** + * This notice applies to any and all portions of this file + * that are not between comment pairs USER CODE BEGIN and + * USER CODE END. Other portions of this file, whether + * inserted by the user or by software development tools + * are owned by their respective copyright owners. + * + * Copyright (c) 2017 STMicroelectronics International N.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted, provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of other + * contributors to this software may be used to endorse or promote products + * derived from this software without specific written permission. + * 4. This software, including modifications and/or derivative works of this + * software, must execute solely and exclusively on microcontroller or + * microprocessor devices manufactured by or for STMicroelectronics. + * 5. Redistribution and use of this software other than as permitted under + * this license is void and will automatically terminate your rights under + * this license. + * + * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY + * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT + * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __usart_H +#define __usart_H +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal.h" +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern UART_HandleTypeDef huart4; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +extern void _Error_Handler(char *, int); + +void MX_UART4_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif +#endif /*__ usart_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/Makefile b/Makefile index 081f17b8..e2033d82 100644 --- a/Makefile +++ b/Makefile @@ -50,6 +50,7 @@ C_SOURCES = \ Src/spi.c \ Src/stm32f4xx_hal_msp.c \ Src/can.c \ + Src/usart.c \ Src/usbd_conf.c \ Src/usbd_desc.c \ Src/usb_device.c \ @@ -74,6 +75,7 @@ C_SOURCES = \ Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc_ex.c \ Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pcd.c \ Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pcd_ex.c \ + Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c \ Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.c \ Src/usbd_cdc_if.c \ Src/syscalls.c \ diff --git a/Odrive.ioc b/Odrive.ioc index b7bd70f6..6bc3ca05 100755 --- a/Odrive.ioc +++ b/Odrive.ioc @@ -92,8 +92,9 @@ Mcu.IP10=TIM2 Mcu.IP11=TIM3 Mcu.IP12=TIM4 Mcu.IP13=TIM8 -Mcu.IP14=USB_DEVICE -Mcu.IP15=USB_OTG_FS +Mcu.IP14=UART4 +Mcu.IP15=USB_DEVICE +Mcu.IP16=USB_OTG_FS Mcu.IP2=ADC3 Mcu.IP3=CAN1 Mcu.IP4=FREERTOS @@ -102,7 +103,7 @@ Mcu.IP6=RCC Mcu.IP7=SPI3 Mcu.IP8=SYS Mcu.IP9=TIM1 -Mcu.IPNb=16 +Mcu.IPNb=17 Mcu.Name=STM32F405RGTx Mcu.Package=LQFP64 Mcu.Pin0=PC13-ANTI_TAMP @@ -169,8 +170,7 @@ MxDb.Version=DB.4.0.220 NVIC.ADC_IRQn=true\:5\:0\:false\:false\:true\:true NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false -NVIC.EXTI0_IRQn=true\:0\:0\:false\:false\:true\:false -NVIC.EXTI2_IRQn=true\:0\:0\:false\:false\:true\:false +NVIC.EXTI2_IRQn=true\:0\:0\:false\:false\:false\:false NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false @@ -184,12 +184,14 @@ PA0-WKUP.GPIOParameters=GPIO_PuPd,GPIO_Label PA0-WKUP.GPIO_Label=GPIO_1 PA0-WKUP.GPIO_PuPd=GPIO_PULLDOWN PA0-WKUP.Locked=true -PA0-WKUP.Signal=GPXTI0 +PA0-WKUP.Signal=SharedStack_PA0 +PA0-WKUP.Stacked=true PA1.GPIOParameters=GPIO_PuPd,GPIO_Label PA1.GPIO_Label=GPIO_2 PA1.GPIO_PuPd=GPIO_NOPULL PA1.Locked=true -PA1.Signal=GPIO_Input +PA1.Signal=SharedStack_PA1 +PA1.Stacked=true PA10.GPIOParameters=GPIO_Label PA10.GPIO_Label=M0_CH PA10.Locked=true @@ -398,7 +400,7 @@ ProjectManager.StackSize=0x800 ProjectManager.TargetToolchain=SW4STM32 ProjectManager.ToolChainLocation= ProjectManager.UnderRoot=true -ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL,2-MX_ADC1_Init-ADC1-false-HAL,3-MX_ADC2_Init-ADC2-false-HAL,4-MX_CAN1_Init-CAN1-false-HAL,5-MX_TIM1_Init-TIM1-false-HAL,6-MX_TIM8_Init-TIM8-false-HAL,7-MX_TIM3_Init-TIM3-false-HAL,8-MX_TIM4_Init-TIM4-false-HAL,9-MX_SPI3_Init-SPI3-false-HAL,10-MX_ADC3_Init-ADC3-false-HAL,11-SystemClock_Config-RCC-false-HAL,12-MX_TIM2_Init-TIM2-false-HAL,13-MX_USB_DEVICE_Init-USB_DEVICE-false-HAL +ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL,2-MX_ADC1_Init-ADC1-false-HAL,3-MX_ADC2_Init-ADC2-false-HAL,4-MX_CAN1_Init-CAN1-false-HAL,5-MX_TIM1_Init-TIM1-false-HAL,6-MX_TIM8_Init-TIM8-false-HAL,7-MX_TIM3_Init-TIM3-false-HAL,8-MX_TIM4_Init-TIM4-false-HAL,9-MX_SPI3_Init-SPI3-false-HAL,10-MX_ADC3_Init-ADC3-false-HAL,11-SystemClock_Config-RCC-false-HAL,12-MX_TIM2_Init-TIM2-false-HAL,13-MX_USB_DEVICE_Init-USB_DEVICE-false-HAL,14-MX_UART4_Init-UART4-false-HAL RCC.48MHZClocksFreq_Value=48000000 RCC.AHBFreq_Value=168000000 RCC.APB1CLKDivider=RCC_HCLK_DIV4 @@ -464,8 +466,6 @@ SH.ADCx_IN5.ConfNb=2 SH.ADCx_IN6.0=ADC1_IN6,IN6 SH.ADCx_IN6.1=ADC2_IN6,IN6 SH.ADCx_IN6.ConfNb=2 -SH.GPXTI0.0=GPIO_EXTI0 -SH.GPXTI0.ConfNb=1 SH.GPXTI2.0=GPIO_EXTI2 SH.GPXTI2.ConfNb=1 SH.S_TIM1_CH1.0=TIM1_CH1,PWM Generation1 CH1 CH1N @@ -492,6 +492,12 @@ SH.S_TIM8_CH2.0=TIM8_CH2,PWM Generation2 CH2 CH2N SH.S_TIM8_CH2.ConfNb=1 SH.S_TIM8_CH3.0=TIM8_CH3,PWM Generation3 CH3 CH3N SH.S_TIM8_CH3.ConfNb=1 +SH.SharedStack_PA0.0=GPIO_EXTI0+0 +SH.SharedStack_PA0.1=UART4_TX,Asynchronous +SH.SharedStack_PA0.ConfNb=2 +SH.SharedStack_PA1.0=GPIO_Input+0 +SH.SharedStack_PA1.1=UART4_RX,Asynchronous +SH.SharedStack_PA1.ConfNb=2 SPI3.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_16 SPI3.CLKPhase=SPI_PHASE_2EDGE SPI3.CalculateBaudRate=2.625 MBits/s @@ -555,6 +561,8 @@ TIM8.OffStateIDLEMode=TIM_OSSI_ENABLE TIM8.OffStateRunMode=TIM_OSSR_ENABLE TIM8.Period=TIM_1_8_PERIOD_CLOCKS TIM8.TIM_MasterOutputTrigger=TIM_TRGO_UPDATE +UART4.IPParameters=VirtualMode +UART4.VirtualMode=Asynchronous USB_DEVICE.CLASS_NAME_FS=CDC USB_DEVICE.IPParameters=VirtualMode-CDC_FS,VirtualModeFS,CLASS_NAME_FS,MANUFACTURER_STRING-CDC_FS,PRODUCT_STRING_CDC_FS,VID-CDC_FS,PID_CDC_FS,SERIALNUMBER_STRING_CDC_FS USB_DEVICE.MANUFACTURER_STRING-CDC_FS=ODrive diff --git a/Src/gpio.c b/Src/gpio.c index a7752882..eaa8b365 100644 --- a/Src/gpio.c +++ b/Src/gpio.c @@ -71,6 +71,8 @@ * Output * EVENT_OUT * EXTI + PA0-WKUP ------> SharedStack_PA0 + PA1 ------> SharedStack_PA1 */ void MX_GPIO_Init(void) { @@ -100,14 +102,30 @@ void MX_GPIO_Init(void) GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); - /*Configure GPIO pins : PAPin PAPin */ - GPIO_InitStruct.Pin = GPIO_1_Pin|GPIO_3_Pin; + /*Configure GPIO pin : PtPin */ + GPIO_InitStruct.Pin = GPIO_1_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF8_UART4; + HAL_GPIO_Init(GPIO_1_GPIO_Port, &GPIO_InitStruct); + + /*Configure GPIO pin : PtPin */ + GPIO_InitStruct.Pin = GPIO_2_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF8_UART4; + HAL_GPIO_Init(GPIO_2_GPIO_Port, &GPIO_InitStruct); + + /*Configure GPIO pin : PtPin */ + GPIO_InitStruct.Pin = GPIO_3_Pin; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; GPIO_InitStruct.Pull = GPIO_PULLDOWN; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + HAL_GPIO_Init(GPIO_3_GPIO_Port, &GPIO_InitStruct); - /*Configure GPIO pins : PAPin PAPin PAPin */ - GPIO_InitStruct.Pin = GPIO_2_Pin|GPIO_4_Pin|M0_ENC_Z_Pin; + /*Configure GPIO pins : PAPin PAPin */ + GPIO_InitStruct.Pin = GPIO_4_Pin|M0_ENC_Z_Pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); @@ -132,9 +150,6 @@ void MX_GPIO_Init(void) HAL_GPIO_Init(nFAULT_GPIO_Port, &GPIO_InitStruct); /* EXTI interrupt init*/ - HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); - HAL_NVIC_EnableIRQ(EXTI0_IRQn); - HAL_NVIC_SetPriority(EXTI2_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI2_IRQn); @@ -143,6 +158,43 @@ void MX_GPIO_Init(void) /* USER CODE BEGIN 2 */ #endif // End GPIO Include +void SetGPIO12toUART() { + GPIO_InitTypeDef GPIO_InitStruct; + + HAL_NVIC_DisableIRQ(EXTI0_IRQn); + + GPIO_InitStruct.Pin = GPIO_1_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF8_UART4; + HAL_GPIO_Init(GPIO_1_GPIO_Port, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = GPIO_2_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF8_UART4; + HAL_GPIO_Init(GPIO_2_GPIO_Port, &GPIO_InitStruct); +} + +void SetGPIO12toStepDir() { + GPIO_InitTypeDef GPIO_InitStruct; + + GPIO_InitStruct.Pin = GPIO_1_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + HAL_GPIO_Init(GPIO_1_GPIO_Port, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = GPIO_2_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIO_2_GPIO_Port, &GPIO_InitStruct); + + HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(EXTI0_IRQn); +} + //Dispatch processing of external interrupts based on source void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { //Step signals for M0 and M1 diff --git a/Src/main.c b/Src/main.c index ddf6bb29..2890fec2 100644 --- a/Src/main.c +++ b/Src/main.c @@ -53,6 +53,7 @@ #include "can.h" #include "spi.h" #include "tim.h" +#include "usart.h" #include "usb_device.h" #include "gpio.h" @@ -115,6 +116,7 @@ int main(void) MX_SPI3_Init(); MX_ADC3_Init(); MX_TIM2_Init(); + MX_UART4_Init(); /* USER CODE BEGIN 2 */ diff --git a/Src/stm32f4xx_it.c b/Src/stm32f4xx_it.c index 8b218e23..2d00e4c7 100644 --- a/Src/stm32f4xx_it.c +++ b/Src/stm32f4xx_it.c @@ -171,34 +171,6 @@ void SysTick_Handler(void) /* please refer to the startup file (startup_stm32f4xx.s). */ /******************************************************************************/ -/** -* @brief This function handles EXTI line0 interrupt. -*/ -void EXTI0_IRQHandler(void) -{ - /* USER CODE BEGIN EXTI0_IRQn 0 */ - - /* USER CODE END EXTI0_IRQn 0 */ - HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); - /* USER CODE BEGIN EXTI0_IRQn 1 */ - - /* USER CODE END EXTI0_IRQn 1 */ -} - -/** -* @brief This function handles EXTI line2 interrupt. -*/ -void EXTI2_IRQHandler(void) -{ - /* USER CODE BEGIN EXTI2_IRQn 0 */ - - /* USER CODE END EXTI2_IRQn 0 */ - HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2); - /* USER CODE BEGIN EXTI2_IRQn 1 */ - - /* USER CODE END EXTI2_IRQn 1 */ -} - /** * @brief This function handles ADC1, ADC2 and ADC3 global interrupts. */ @@ -267,5 +239,22 @@ void ADC_IRQ_Dispatch(ADC_HandleTypeDef* hadc, ADC_handler_t callback) { } } + +/** +* @brief This function handles EXTI line0 interrupt. +*/ +void EXTI0_IRQHandler(void) +{ + HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); +} + +/** +* @brief This function handles EXTI line2 interrupt. +*/ +void EXTI2_IRQHandler(void) +{ + HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2); +} + /* USER CODE END 1 */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/Src/usart.c b/Src/usart.c new file mode 100644 index 00000000..a472eaf2 --- /dev/null +++ b/Src/usart.c @@ -0,0 +1,151 @@ +/** + ****************************************************************************** + * File Name : USART.c + * Description : This file provides code for the configuration + * of the USART instances. + ****************************************************************************** + * This notice applies to any and all portions of this file + * that are not between comment pairs USER CODE BEGIN and + * USER CODE END. Other portions of this file, whether + * inserted by the user or by software development tools + * are owned by their respective copyright owners. + * + * Copyright (c) 2017 STMicroelectronics International N.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted, provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of other + * contributors to this software may be used to endorse or promote products + * derived from this software without specific written permission. + * 4. This software, including modifications and/or derivative works of this + * software, must execute solely and exclusively on microcontroller or + * microprocessor devices manufactured by or for STMicroelectronics. + * 5. Redistribution and use of this software other than as permitted under + * this license is void and will automatically terminate your rights under + * this license. + * + * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY + * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT + * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usart.h" + +#include "gpio.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +UART_HandleTypeDef huart4; + +/* UART4 init function */ +void MX_UART4_Init(void) +{ + + huart4.Instance = UART4; + huart4.Init.BaudRate = 115200; + huart4.Init.WordLength = UART_WORDLENGTH_8B; + huart4.Init.StopBits = UART_STOPBITS_1; + huart4.Init.Parity = UART_PARITY_NONE; + huart4.Init.Mode = UART_MODE_TX_RX; + huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE; + huart4.Init.OverSampling = UART_OVERSAMPLING_16; + if (HAL_UART_Init(&huart4) != HAL_OK) + { + _Error_Handler(__FILE__, __LINE__); + } + +} + +void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) +{ + + GPIO_InitTypeDef GPIO_InitStruct; + if(uartHandle->Instance==UART4) + { + /* USER CODE BEGIN UART4_MspInit 0 */ + + /* USER CODE END UART4_MspInit 0 */ + /* UART4 clock enable */ + __HAL_RCC_UART4_CLK_ENABLE(); + + /**UART4 GPIO Configuration + PA0-WKUP ------> UART4_TX + PA1 ------> UART4_RX + */ + GPIO_InitStruct.Pin = GPIO_1_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF8_UART4; + HAL_GPIO_Init(GPIO_1_GPIO_Port, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = GPIO_2_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF8_UART4; + HAL_GPIO_Init(GPIO_2_GPIO_Port, &GPIO_InitStruct); + + /* USER CODE BEGIN UART4_MspInit 1 */ + + /* USER CODE END UART4_MspInit 1 */ + } +} + +void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle) +{ + + if(uartHandle->Instance==UART4) + { + /* USER CODE BEGIN UART4_MspDeInit 0 */ + + /* USER CODE END UART4_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_UART4_CLK_DISABLE(); + + /**UART4 GPIO Configuration + PA0-WKUP ------> UART4_TX + PA1 ------> UART4_RX + */ + HAL_GPIO_DeInit(GPIOA, GPIO_1_Pin|GPIO_2_Pin); + + /* USER CODE BEGIN UART4_MspDeInit 1 */ + + /* USER CODE END UART4_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ From b82bb9a0c2a8a335412ffdf3b2f8e5e2babf8098 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sat, 23 Sep 2017 04:14:14 -0700 Subject: [PATCH 11/35] Enable UART Rx DMA stream --- Inc/dma.h | 88 ++++++++++++++++++++++++++++++++++++++++++++ Inc/stm32f4xx_it.h | 1 + Odrive.ioc | 44 ++++++++++++++-------- Src/dma.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++ Src/freertos.c | 9 +++++ Src/main.c | 2 + Src/stm32f4xx_it.c | 15 ++++++++ Src/usart.c | 23 ++++++++++++ 8 files changed, 258 insertions(+), 15 deletions(-) create mode 100644 Inc/dma.h create mode 100644 Src/dma.c diff --git a/Inc/dma.h b/Inc/dma.h new file mode 100644 index 00000000..1d73731f --- /dev/null +++ b/Inc/dma.h @@ -0,0 +1,88 @@ +/** + ****************************************************************************** + * File Name : dma.h + * Description : This file contains all the function prototypes for + * the dma.c file + ****************************************************************************** + * This notice applies to any and all portions of this file + * that are not between comment pairs USER CODE BEGIN and + * USER CODE END. Other portions of this file, whether + * inserted by the user or by software development tools + * are owned by their respective copyright owners. + * + * Copyright (c) 2017 STMicroelectronics International N.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted, provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of other + * contributors to this software may be used to endorse or promote products + * derived from this software without specific written permission. + * 4. This software, including modifications and/or derivative works of this + * software, must execute solely and exclusively on microcontroller or + * microprocessor devices manufactured by or for STMicroelectronics. + * 5. Redistribution and use of this software other than as permitted under + * this license is void and will automatically terminate your rights under + * this license. + * + * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY + * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT + * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __dma_H +#define __dma_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal.h" +#include "main.h" + +/* DMA memory to memory transfer handles -------------------------------------*/ +extern void _Error_Handler(char*, int); + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_DMA_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __dma_H */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/Inc/stm32f4xx_it.h b/Inc/stm32f4xx_it.h index e7b8672f..f9b4a6b7 100644 --- a/Inc/stm32f4xx_it.h +++ b/Inc/stm32f4xx_it.h @@ -52,6 +52,7 @@ void BusFault_Handler(void); void UsageFault_Handler(void); void DebugMon_Handler(void); void SysTick_Handler(void); +void DMA1_Stream2_IRQHandler(void); void ADC_IRQHandler(void); void OTG_FS_IRQHandler(void); diff --git a/Odrive.ioc b/Odrive.ioc index 6bc3ca05..dac67e06 100755 --- a/Odrive.ioc +++ b/Odrive.ioc @@ -80,6 +80,18 @@ CAN1.BS2=CAN_BS2_1TQ CAN1.CalculateTimeBit=1142 CAN1.CalculateTimeQuantum=380.95238095238096 CAN1.IPParameters=CalculateTimeQuantum,CalculateTimeBit,BS1,BS2 +Dma.Request0=UART4_RX +Dma.RequestsNb=1 +Dma.UART4_RX.0.Direction=DMA_PERIPH_TO_MEMORY +Dma.UART4_RX.0.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.UART4_RX.0.Instance=DMA1_Stream2 +Dma.UART4_RX.0.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.UART4_RX.0.MemInc=DMA_MINC_ENABLE +Dma.UART4_RX.0.Mode=DMA_CIRCULAR +Dma.UART4_RX.0.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.UART4_RX.0.PeriphInc=DMA_PINC_DISABLE +Dma.UART4_RX.0.Priority=DMA_PRIORITY_LOW +Dma.UART4_RX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode FREERTOS.INCLUDE_vTaskDelayUntil=1 FREERTOS.IPParameters=Tasks01,INCLUDE_vTaskDelayUntil FREERTOS.Tasks01=defaultTask,-3,256,StartDefaultTask,Default @@ -88,22 +100,23 @@ KeepUserPlacement=true Mcu.Family=STM32F4 Mcu.IP0=ADC1 Mcu.IP1=ADC2 -Mcu.IP10=TIM2 -Mcu.IP11=TIM3 -Mcu.IP12=TIM4 -Mcu.IP13=TIM8 -Mcu.IP14=UART4 -Mcu.IP15=USB_DEVICE -Mcu.IP16=USB_OTG_FS +Mcu.IP10=TIM1 +Mcu.IP11=TIM2 +Mcu.IP12=TIM3 +Mcu.IP13=TIM4 +Mcu.IP14=TIM8 +Mcu.IP15=UART4 +Mcu.IP16=USB_DEVICE +Mcu.IP17=USB_OTG_FS Mcu.IP2=ADC3 Mcu.IP3=CAN1 -Mcu.IP4=FREERTOS -Mcu.IP5=NVIC -Mcu.IP6=RCC -Mcu.IP7=SPI3 -Mcu.IP8=SYS -Mcu.IP9=TIM1 -Mcu.IPNb=17 +Mcu.IP4=DMA +Mcu.IP5=FREERTOS +Mcu.IP6=NVIC +Mcu.IP7=RCC +Mcu.IP8=SPI3 +Mcu.IP9=SYS +Mcu.IPNb=18 Mcu.Name=STM32F405RGTx Mcu.Package=LQFP64 Mcu.Pin0=PC13-ANTI_TAMP @@ -169,6 +182,7 @@ MxCube.Version=4.22.0 MxDb.Version=DB.4.0.220 NVIC.ADC_IRQn=true\:5\:0\:false\:false\:true\:true NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false +NVIC.DMA1_Stream2_IRQn=true\:5\:0\:false\:false\:true\:true NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false NVIC.EXTI2_IRQn=true\:0\:0\:false\:false\:false\:false NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false @@ -400,7 +414,7 @@ ProjectManager.StackSize=0x800 ProjectManager.TargetToolchain=SW4STM32 ProjectManager.ToolChainLocation= ProjectManager.UnderRoot=true -ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL,2-MX_ADC1_Init-ADC1-false-HAL,3-MX_ADC2_Init-ADC2-false-HAL,4-MX_CAN1_Init-CAN1-false-HAL,5-MX_TIM1_Init-TIM1-false-HAL,6-MX_TIM8_Init-TIM8-false-HAL,7-MX_TIM3_Init-TIM3-false-HAL,8-MX_TIM4_Init-TIM4-false-HAL,9-MX_SPI3_Init-SPI3-false-HAL,10-MX_ADC3_Init-ADC3-false-HAL,11-SystemClock_Config-RCC-false-HAL,12-MX_TIM2_Init-TIM2-false-HAL,13-MX_USB_DEVICE_Init-USB_DEVICE-false-HAL,14-MX_UART4_Init-UART4-false-HAL +ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL,2-MX_DMA_Init-DMA-false-HAL,3-MX_ADC1_Init-ADC1-false-HAL,4-MX_ADC2_Init-ADC2-false-HAL,5-MX_CAN1_Init-CAN1-false-HAL,6-MX_TIM1_Init-TIM1-false-HAL,7-MX_TIM8_Init-TIM8-false-HAL,8-MX_TIM3_Init-TIM3-false-HAL,9-MX_TIM4_Init-TIM4-false-HAL,10-MX_SPI3_Init-SPI3-false-HAL,11-MX_ADC3_Init-ADC3-false-HAL,12-SystemClock_Config-RCC-false-HAL,13-MX_TIM2_Init-TIM2-false-HAL,14-MX_USB_DEVICE_Init-USB_DEVICE-false-HAL,15-MX_UART4_Init-UART4-false-HAL RCC.48MHZClocksFreq_Value=48000000 RCC.AHBFreq_Value=168000000 RCC.APB1CLKDivider=RCC_HCLK_DIV4 diff --git a/Src/dma.c b/Src/dma.c new file mode 100644 index 00000000..615d014d --- /dev/null +++ b/Src/dma.c @@ -0,0 +1,91 @@ +/** + ****************************************************************************** + * File Name : dma.c + * Description : This file provides code for the configuration + * of all the requested memory to memory DMA transfers. + ****************************************************************************** + * This notice applies to any and all portions of this file + * that are not between comment pairs USER CODE BEGIN and + * USER CODE END. Other portions of this file, whether + * inserted by the user or by software development tools + * are owned by their respective copyright owners. + * + * Copyright (c) 2017 STMicroelectronics International N.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted, provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of other + * contributors to this software may be used to endorse or promote products + * derived from this software without specific written permission. + * 4. This software, including modifications and/or derivative works of this + * software, must execute solely and exclusively on microcontroller or + * microprocessor devices manufactured by or for STMicroelectronics. + * 5. Redistribution and use of this software other than as permitted under + * this license is void and will automatically terminate your rights under + * this license. + * + * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY + * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT + * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ +/* Includes ------------------------------------------------------------------*/ +#include "dma.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/*----------------------------------------------------------------------------*/ +/* Configure DMA */ +/*----------------------------------------------------------------------------*/ + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/** + * Enable DMA controller clock + */ +void MX_DMA_Init(void) +{ + /* DMA controller clock enable */ + __HAL_RCC_DMA1_CLK_ENABLE(); + + /* DMA interrupt init */ + /* DMA1_Stream2_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA1_Stream2_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn); + +} + +/* USER CODE BEGIN 2 */ + +/* USER CODE END 2 */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/Src/freertos.c b/Src/freertos.c index c445cdd6..e62c1813 100644 --- a/Src/freertos.c +++ b/Src/freertos.c @@ -145,6 +145,15 @@ void StartDefaultTask(void const * argument) // Thread to handle deffered processing of USB interrupt void usb_cmd_thread(void const * argument) { + //DMA open loop continous circular buffer + //1ms delay periodic, chase DMA ptr around, on new data: + // Check for start char + // copy into parse-buffer + // check for end-char + // checksum, etc. + + + for (;;) { // Wait for signalling from USB interrupt (OTG_FS_IRQHandler) osSemaphoreWait(sem_usb_irq, osWaitForever); diff --git a/Src/main.c b/Src/main.c index 2890fec2..f773ff67 100644 --- a/Src/main.c +++ b/Src/main.c @@ -51,6 +51,7 @@ #include "cmsis_os.h" #include "adc.h" #include "can.h" +#include "dma.h" #include "spi.h" #include "tim.h" #include "usart.h" @@ -106,6 +107,7 @@ int main(void) /* Initialize all configured peripherals */ MX_GPIO_Init(); + MX_DMA_Init(); MX_ADC1_Init(); MX_ADC2_Init(); MX_CAN1_Init(); diff --git a/Src/stm32f4xx_it.c b/Src/stm32f4xx_it.c index 2d00e4c7..7c5c849e 100644 --- a/Src/stm32f4xx_it.c +++ b/Src/stm32f4xx_it.c @@ -54,6 +54,7 @@ extern PCD_HandleTypeDef hpcd_USB_OTG_FS; extern ADC_HandleTypeDef hadc1; extern ADC_HandleTypeDef hadc2; extern ADC_HandleTypeDef hadc3; +extern DMA_HandleTypeDef hdma_uart4_rx; /******************************************************************************/ /* Cortex-M4 Processor Interruption and Exception Handlers */ @@ -171,6 +172,20 @@ void SysTick_Handler(void) /* please refer to the startup file (startup_stm32f4xx.s). */ /******************************************************************************/ +/** +* @brief This function handles DMA1 stream2 global interrupt. +*/ +void DMA1_Stream2_IRQHandler(void) +{ + /* USER CODE BEGIN DMA1_Stream2_IRQn 0 */ + + /* USER CODE END DMA1_Stream2_IRQn 0 */ + HAL_DMA_IRQHandler(&hdma_uart4_rx); + /* USER CODE BEGIN DMA1_Stream2_IRQn 1 */ + + /* USER CODE END DMA1_Stream2_IRQn 1 */ +} + /** * @brief This function handles ADC1, ADC2 and ADC3 global interrupts. */ diff --git a/Src/usart.c b/Src/usart.c index a472eaf2..a0842cf9 100644 --- a/Src/usart.c +++ b/Src/usart.c @@ -51,12 +51,14 @@ #include "usart.h" #include "gpio.h" +#include "dma.h" /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ UART_HandleTypeDef huart4; +DMA_HandleTypeDef hdma_uart4_rx; /* UART4 init function */ void MX_UART4_Init(void) @@ -107,6 +109,25 @@ void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) GPIO_InitStruct.Alternate = GPIO_AF8_UART4; HAL_GPIO_Init(GPIO_2_GPIO_Port, &GPIO_InitStruct); + /* UART4 DMA Init */ + /* UART4_RX Init */ + hdma_uart4_rx.Instance = DMA1_Stream2; + hdma_uart4_rx.Init.Channel = DMA_CHANNEL_4; + hdma_uart4_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_uart4_rx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_uart4_rx.Init.MemInc = DMA_MINC_ENABLE; + hdma_uart4_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_uart4_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_uart4_rx.Init.Mode = DMA_CIRCULAR; + hdma_uart4_rx.Init.Priority = DMA_PRIORITY_LOW; + hdma_uart4_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + if (HAL_DMA_Init(&hdma_uart4_rx) != HAL_OK) + { + _Error_Handler(__FILE__, __LINE__); + } + + __HAL_LINKDMA(uartHandle,hdmarx,hdma_uart4_rx); + /* USER CODE BEGIN UART4_MspInit 1 */ /* USER CODE END UART4_MspInit 1 */ @@ -130,6 +151,8 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle) */ HAL_GPIO_DeInit(GPIOA, GPIO_1_Pin|GPIO_2_Pin); + /* UART4 DMA DeInit */ + HAL_DMA_DeInit(uartHandle->hdmarx); /* USER CODE BEGIN UART4_MspDeInit 1 */ /* USER CODE END UART4_MspDeInit 1 */ From 9abec8af005d5eaf9115e7070b6164a86980a0c8 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sat, 23 Sep 2017 20:31:43 -0700 Subject: [PATCH 12/35] implement UART read state machine --- Makefile | 1 + Src/freertos.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e2033d82..a852af35 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,7 @@ C_SOURCES = \ Src/stm32f4xx_hal_msp.c \ Src/can.c \ Src/usart.c \ + Src/dma.c \ Src/usbd_conf.c \ Src/usbd_desc.c \ Src/usb_device.c \ diff --git a/Src/freertos.c b/Src/freertos.c index e62c1813..41094c23 100644 --- a/Src/freertos.c +++ b/Src/freertos.c @@ -54,6 +54,7 @@ /* USER CODE BEGIN Includes */ #include "freertos_vars.h" #include "low_level.h" +#include "usart.h" #include "version.h" /* USER CODE END Includes */ @@ -142,6 +143,7 @@ void StartDefaultTask(void const * argument) /* USER CODE BEGIN Application */ +//TODO move this to a different file // Thread to handle deffered processing of USB interrupt void usb_cmd_thread(void const * argument) { @@ -152,7 +154,62 @@ void usb_cmd_thread(void const * argument) { // check for end-char // checksum, etc. - + #define UART_BUFFER_SIZE 64 + static uint8_t dma_circ_buffer[UART_BUFFER_SIZE]; + static uint8_t parse_buffer[UART_BUFFER_SIZE]; + + // DMA is set up to recieve in a circular buffer forever. + // We dont use interrupts to fetch the data, instead we periodically read + // data out of the circular buffer into a parse buffer, controlled by a state machine + HAL_UART_Receive_DMA(&huart4, dma_circ_buffer, sizeof(dma_circ_buffer)); + + uint32_t last_rcv_idx = UART_BUFFER_SIZE - huart4.hdmarx->Instance->NDTR; + // Re-run state-machine forever + for (;;) { + //Inialize recieve state machine + bool reset_read_state = false; + bool read_active = false; + uint32_t parse_buffer_idx = 0; + //Run state machine until reset + do { + // Fetch the circular buffer "write pointer", where it would write next + uint32_t rcv_idx = UART_BUFFER_SIZE - huart4.hdmarx->Instance->NDTR; + // During sleeping, we may have fallen several characters behind, so we keep + // going until we are caught up, before we sleep again + while (rcv_idx != last_rcv_idx) { + // Fetch the next char, rotate read ptr + uint8_t c = dma_circ_buffer[last_rcv_idx]; + if (++last_rcv_idx == UART_BUFFER_SIZE) + last_rcv_idx = 0; + // Look for start character + if (c == '$') { + read_active = true; + continue; // do not record start char + } + // Record into parse buffer when actively reading + if (read_active) { + parse_buffer[parse_buffer_idx++] = c; + if (c == '\r' || c == '\n') { + // End of command string: exchange end char with terminating null + parse_buffer[parse_buffer_idx-1] = '\0'; + osDelay(1); + // Reset receieve state machine + reset_read_state = true; + break; + } else if (parse_buffer_idx == UART_BUFFER_SIZE - 1) { + // We are not at end of command, and receiving another character after this + // would go into the last slot, which is reserved for terminating null. + // We have effectively overflowed parse buffer: abort. + reset_read_state = true; + break; + } + } + } + // When we reach here, we are out of immediate characters to fetch out of buffer + // So we sleep for a bit. + osDelay(1); + } while (!reset_read_state); + } for (;;) { // Wait for signalling from USB interrupt (OTG_FS_IRQHandler) From 57273d04d4929a7d921a63a8c555dfd674fdba0d Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sat, 23 Sep 2017 21:10:48 -0700 Subject: [PATCH 13/35] add ! as alternative end char, do parsing --- Src/freertos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Src/freertos.c b/Src/freertos.c index 41094c23..630b5a2c 100644 --- a/Src/freertos.c +++ b/Src/freertos.c @@ -189,10 +189,10 @@ void usb_cmd_thread(void const * argument) { // Record into parse buffer when actively reading if (read_active) { parse_buffer[parse_buffer_idx++] = c; - if (c == '\r' || c == '\n') { + if (c == '\r' || c == '\n' || c == "!") { // End of command string: exchange end char with terminating null parse_buffer[parse_buffer_idx-1] = '\0'; - osDelay(1); + motor_parse_cmd(parse_buffer, parse_buffer_idx); // Reset receieve state machine reset_read_state = true; break; From 3c6cec513e985c2527e93a95519d0f161d72d1f3 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sat, 23 Sep 2017 21:11:23 -0700 Subject: [PATCH 14/35] fix char vs str mistake --- Src/freertos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/freertos.c b/Src/freertos.c index 630b5a2c..a61e7ee9 100644 --- a/Src/freertos.c +++ b/Src/freertos.c @@ -189,7 +189,7 @@ void usb_cmd_thread(void const * argument) { // Record into parse buffer when actively reading if (read_active) { parse_buffer[parse_buffer_idx++] = c; - if (c == '\r' || c == '\n' || c == "!") { + if (c == '\r' || c == '\n' || c == '!') { // End of command string: exchange end char with terminating null parse_buffer[parse_buffer_idx-1] = '\0'; motor_parse_cmd(parse_buffer, parse_buffer_idx); From 0782ef1b2a20980399ef0a61636aab5d5db2635f Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Fri, 29 Sep 2017 20:59:57 -0700 Subject: [PATCH 15/35] Note about shuntAmpGain and currentLim --- MotorControl/low_level.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MotorControl/low_level.c b/MotorControl/low_level.c index 83f284f6..1d1da1b6 100755 --- a/MotorControl/low_level.c +++ b/MotorControl/low_level.c @@ -84,7 +84,7 @@ Motor_t motors[] = { .shunt_conductance = 1.0f/0.0005f, //[S] .phase_current_rev_gain = 0.0f, // to be set by DRV8301_setup .current_control = { - // .current_lim = 75.0f, //[A] // Note: consistent with 40v/v gain, TODO: auto limit from gain settings + // .current_lim = 75.0f, //[A] // If setting higher than 75A, you MUST change DRV8301_ShuntAmpGain. TODO: make this automatic .current_lim = 10.0f, //[A] .p_gain = 0.0f, // [V/A] should be auto set after resistance and inductance measurement .i_gain = 0.0f, // [V/As] should be auto set after resistance and inductance measurement @@ -167,7 +167,7 @@ Motor_t motors[] = { .shunt_conductance = 1.0f/0.0005f, //[S] .phase_current_rev_gain = 0.0f, // to be set by DRV8301_setup .current_control = { - // .current_lim = 75.0f, //[A] // Note: consistent with 40v/v gain, TODO: auto limit from gain settings + // .current_lim = 75.0f, //[A] // If setting higher than 75A, you MUST change DRV8301_ShuntAmpGain. TODO: make this automatic .current_lim = 10.0f, //[A] .p_gain = 0.0f, // [V/A] should be auto set after resistance and inductance measurement .i_gain = 0.0f, // [V/As] should be auto set after resistance and inductance measurement From b49669e402bf74413d4ad05bd0a2e1244b16cc5a Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sun, 1 Oct 2017 19:46:55 -0700 Subject: [PATCH 16/35] fix forgetting to save v3.2 board version of main.h --- Inc/main.h | 5 +++ Inc/prev_board_ver/main.h | 91 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 Inc/prev_board_ver/main.h diff --git a/Inc/main.h b/Inc/main.h index a2fdb772..800fe244 100644 --- a/Inc/main.h +++ b/Inc/main.h @@ -55,6 +55,10 @@ #define HW_VERSION_MAJOR 3 #define HW_VERSION_MINOR 3 +#if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 1 \ +|| HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 2 +#include "prev_board_ver/main_V3_2.h" +#else /* USER CODE END Includes */ /* Private define ------------------------------------------------------------*/ @@ -149,6 +153,7 @@ #define M1_ENC_B_GPIO_Port GPIOB /* USER CODE BEGIN Private defines */ +#endif #define CURRENT_MEAS_PERIOD ((float)(2*TIM_1_8_PERIOD_CLOCKS)/(float)TIM_1_8_CLOCK_HZ) #define CURRENT_MEAS_HZ (TIM_1_8_CLOCK_HZ/(2*TIM_1_8_PERIOD_CLOCKS)) diff --git a/Inc/prev_board_ver/main.h b/Inc/prev_board_ver/main.h new file mode 100644 index 00000000..8c8eff81 --- /dev/null +++ b/Inc/prev_board_ver/main.h @@ -0,0 +1,91 @@ + +/* Private define ------------------------------------------------------------*/ +#define TIM_1_8_CLOCK_HZ 168000000 +#define TIM_1_8_PERIOD_CLOCKS 10192 +#define TIM_1_8_DEADTIME_CLOCKS 20 +#define TIM_APB1_CLOCK_HZ 84000000 +#define TIM_APB1_PERIOD_CLOCKS 4096 +#define TIM_APB1_DEADTIME_CLOCKS 40 + +#define M0_nCS_Pin GPIO_PIN_13 +#define M0_nCS_GPIO_Port GPIOC +#define M1_nCS_Pin GPIO_PIN_14 +#define M1_nCS_GPIO_Port GPIOC +#define M1_DC_CAL_Pin GPIO_PIN_15 +#define M1_DC_CAL_GPIO_Port GPIOC +#define M0_IB_Pin GPIO_PIN_0 +#define M0_IB_GPIO_Port GPIOC +#define M0_IC_Pin GPIO_PIN_1 +#define M0_IC_GPIO_Port GPIOC +#define M1_IC_Pin GPIO_PIN_2 +#define M1_IC_GPIO_Port GPIOC +#define M1_IB_Pin GPIO_PIN_3 +#define M1_IB_GPIO_Port GPIOC +#define VBUS_S_Pin GPIO_PIN_0 +#define VBUS_S_GPIO_Port GPIOA +#define M1_TEMP_Pin GPIO_PIN_1 +#define M1_TEMP_GPIO_Port GPIOA +#define AUX_I_Pin GPIO_PIN_2 +#define AUX_I_GPIO_Port GPIOA +#define GPIO_4_Pin GPIO_PIN_3 +#define GPIO_4_GPIO_Port GPIOA +#define GPIO_3_Pin GPIO_PIN_4 +#define GPIO_3_GPIO_Port GPIOA +#define GPIO_3_EXTI_IRQn EXTI4_IRQn +#define GPIO_2_Pin GPIO_PIN_5 +#define GPIO_2_GPIO_Port GPIOA +#define AUX_V_Pin GPIO_PIN_6 +#define AUX_V_GPIO_Port GPIOA +#define M1_AL_Pin GPIO_PIN_7 +#define M1_AL_GPIO_Port GPIOA +#define AUX_TEMP_Pin GPIO_PIN_4 +#define AUX_TEMP_GPIO_Port GPIOC +#define M0_TEMP_Pin GPIO_PIN_5 +#define M0_TEMP_GPIO_Port GPIOC +#define M1_BL_Pin GPIO_PIN_0 +#define M1_BL_GPIO_Port GPIOB +#define M1_CL_Pin GPIO_PIN_1 +#define M1_CL_GPIO_Port GPIOB +#define GPIO_1_Pin GPIO_PIN_2 +#define GPIO_1_GPIO_Port GPIOB +#define GPIO_1_EXTI_IRQn EXTI2_IRQn +#define AUX_L_Pin GPIO_PIN_10 +#define AUX_L_GPIO_Port GPIOB +#define AUX_H_Pin GPIO_PIN_11 +#define AUX_H_GPIO_Port GPIOB +#define EN_GATE_Pin GPIO_PIN_12 +#define EN_GATE_GPIO_Port GPIOB +#define M0_AL_Pin GPIO_PIN_13 +#define M0_AL_GPIO_Port GPIOB +#define M0_BL_Pin GPIO_PIN_14 +#define M0_BL_GPIO_Port GPIOB +#define M0_CL_Pin GPIO_PIN_15 +#define M0_CL_GPIO_Port GPIOB +#define M1_AH_Pin GPIO_PIN_6 +#define M1_AH_GPIO_Port GPIOC +#define M1_BH_Pin GPIO_PIN_7 +#define M1_BH_GPIO_Port GPIOC +#define M1_CH_Pin GPIO_PIN_8 +#define M1_CH_GPIO_Port GPIOC +#define M0_DC_CAL_Pin GPIO_PIN_9 +#define M0_DC_CAL_GPIO_Port GPIOC +#define M0_AH_Pin GPIO_PIN_8 +#define M0_AH_GPIO_Port GPIOA +#define M0_BH_Pin GPIO_PIN_9 +#define M0_BH_GPIO_Port GPIOA +#define M0_CH_Pin GPIO_PIN_10 +#define M0_CH_GPIO_Port GPIOA +#define M0_ENC_Z_Pin GPIO_PIN_15 +#define M0_ENC_Z_GPIO_Port GPIOA +#define nFAULT_Pin GPIO_PIN_2 +#define nFAULT_GPIO_Port GPIOD +#define M1_ENC_Z_Pin GPIO_PIN_3 +#define M1_ENC_Z_GPIO_Port GPIOB +#define M0_ENC_A_Pin GPIO_PIN_4 +#define M0_ENC_A_GPIO_Port GPIOB +#define M0_ENC_B_Pin GPIO_PIN_5 +#define M0_ENC_B_GPIO_Port GPIOB +#define M1_ENC_A_Pin GPIO_PIN_6 +#define M1_ENC_A_GPIO_Port GPIOB +#define M1_ENC_B_Pin GPIO_PIN_7 +#define M1_ENC_B_GPIO_Port GPIOB From 73c7626ff51c657a5a757bd0fe5ed19f149dc9a0 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sun, 1 Oct 2017 19:49:02 -0700 Subject: [PATCH 17/35] rename Inc/prev_board_ver/main_V3_2.h --- Inc/prev_board_ver/{main.h => main_V3_2.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Inc/prev_board_ver/{main.h => main_V3_2.h} (100%) diff --git a/Inc/prev_board_ver/main.h b/Inc/prev_board_ver/main_V3_2.h similarity index 100% rename from Inc/prev_board_ver/main.h rename to Inc/prev_board_ver/main_V3_2.h From cd4ec0aeb985b0d12b42418b934b866e4b2c83f2 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sun, 1 Oct 2017 22:32:03 -0700 Subject: [PATCH 18/35] add vscode intellisense --- .vscode/c_cpp_properties.json | 4 +++- MotorControl/low_level.c | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index bd8d33ee..2fb3414a 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -15,7 +15,9 @@ "${workspaceRoot}/Drivers/CMSIS/Device/ST/STM32F4xx/Include", "${workspaceRoot}/Drivers/CMSIS/Include", "${workspaceRoot}/Inc", - "${workspaceRoot}/MotorControl" + "${workspaceRoot}/MotorControl", + "C:/Program Files (x86)/GNU Tools ARM Embedded/6 2017-q1-update/arm-none-eabi/include", + "C:/Program Files (x86)/GNU Tools ARM Embedded/6 2017-q1-update/lib/gcc/arm-none-eabi/6.3.1/include" ], "defines": [ "_DEBUG", diff --git a/MotorControl/low_level.c b/MotorControl/low_level.c index 1d1da1b6..a7cf7fa2 100755 --- a/MotorControl/low_level.c +++ b/MotorControl/low_level.c @@ -2,12 +2,14 @@ // Because of broken cmsis_os.h, we need to include arm_math first, // otherwise chip specific defines are ommited +#include #include // Sets up the correct chip specifc defines required by arm_math #define ARM_MATH_CM4 #include #include +#include #include #include #include From 6dfc499f4f204b74c5b542399e978048374672be Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Thu, 5 Oct 2017 17:22:02 -0700 Subject: [PATCH 19/35] cleaner rotor mode decode --- MotorControl/low_level.c | 55 +++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/MotorControl/low_level.c b/MotorControl/low_level.c index a7cf7fa2..db44c3b8 100755 --- a/MotorControl/low_level.c +++ b/MotorControl/low_level.c @@ -1214,36 +1214,39 @@ static void update_rotor(Motor_t* motor) { } } +static bool using_encoder(Motor_t* motor) { + if (motor->rotor_mode == ROTOR_MODE_ENCODER || + motor->rotor_mode == ROTOR_MODE_RUN_ENCODER_TEST_SENSORLESS) + return true; + else + return false; +} + +static bool using_sensorless(Motor_t* motor) { + if (motor->rotor_mode == ROTOR_MODE_SENSORLESS) + return true; + else + return false; +} + static float get_rotor_phase(Motor_t* motor) { - switch (motor->rotor_mode) { - case ROTOR_MODE_ENCODER: - case ROTOR_MODE_RUN_ENCODER_TEST_SENSORLESS: - return motor->encoder.phase; - break; - case ROTOR_MODE_SENSORLESS: - return motor->sensorless.phase; - break; - default: - //TODO error handling - return 0.0f; - break; - } + if (using_encoder(motor)) + return motor->encoder.phase; + else if (using_sensorless(motor)) + return motor->sensorless.phase; + else + //TODO error handling + return 0.0f; } static float get_pll_vel(Motor_t* motor) { - switch (motor->rotor_mode) { - case ROTOR_MODE_ENCODER: - case ROTOR_MODE_RUN_ENCODER_TEST_SENSORLESS: - return motor->encoder.pll_vel; - break; - case ROTOR_MODE_SENSORLESS: - return motor->sensorless.pll_vel; - break; - default: - //TODO error handling - return 0.0f; - break; - } + if (using_encoder(motor)) + return motor->encoder.pll_vel; + else if (using_sensorless(motor)) + return motor->sensorless.pll_vel; + else + //TODO error handling + return 0.0f; } static bool spin_up_timestep(Motor_t* motor, float phase, float I_mag) { From 2fce48b24679c41c1ad85f6e3bedb05320d9f9ad Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Tue, 10 Oct 2017 18:48:34 -0700 Subject: [PATCH 20/35] upgrade Cube version --- Inc/stm32f4xx_it.h | 2 ++ Odrive.ioc | 30 +++++++++++++++--------------- Src/usb_device.c | 9 ++++++++- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/Inc/stm32f4xx_it.h b/Inc/stm32f4xx_it.h index f9b4a6b7..56694aec 100644 --- a/Inc/stm32f4xx_it.h +++ b/Inc/stm32f4xx_it.h @@ -40,6 +40,8 @@ #endif /* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal.h" +#include "main.h" /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ /* Exported macro ------------------------------------------------------------*/ diff --git a/Odrive.ioc b/Odrive.ioc index dac67e06..efda2c0c 100755 --- a/Odrive.ioc +++ b/Odrive.ioc @@ -178,22 +178,22 @@ Mcu.Pin9=PA0-WKUP Mcu.PinsNb=56 Mcu.UserConstants=TIM_1_8_CLOCK_HZ,168000000;TIM_1_8_PERIOD_CLOCKS,10192;TIM_1_8_DEADTIME_CLOCKS,20;TIM_APB1_CLOCK_HZ,84000000;TIM_APB1_PERIOD_CLOCKS,4096;TIM_APB1_DEADTIME_CLOCKS,40 Mcu.UserName=STM32F405RGTx -MxCube.Version=4.22.0 -MxDb.Version=DB.4.0.220 -NVIC.ADC_IRQn=true\:5\:0\:false\:false\:true\:true -NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false -NVIC.DMA1_Stream2_IRQn=true\:5\:0\:false\:false\:true\:true -NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false -NVIC.EXTI2_IRQn=true\:0\:0\:false\:false\:false\:false -NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false -NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false -NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false -NVIC.OTG_FS_IRQn=true\:5\:0\:false\:false\:true\:true -NVIC.PendSV_IRQn=true\:15\:0\:false\:false\:false\:true +MxCube.Version=4.22.1 +MxDb.Version=DB.4.0.221 +NVIC.ADC_IRQn=true\:5\:0\:false\:false\:true\:true\:true +NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:true +NVIC.DMA1_Stream2_IRQn=true\:5\:0\:false\:false\:true\:true\:true +NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:true +NVIC.EXTI2_IRQn=true\:0\:0\:false\:false\:false\:false\:true +NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:true +NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:true +NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:true +NVIC.OTG_FS_IRQn=true\:5\:0\:false\:false\:true\:true\:true +NVIC.PendSV_IRQn=true\:15\:0\:false\:false\:false\:true\:true NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 -NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:false\:false -NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:true -NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false +NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:false\:false\:true +NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:true\:true +NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:true PA0-WKUP.GPIOParameters=GPIO_PuPd,GPIO_Label PA0-WKUP.GPIO_Label=GPIO_1 PA0-WKUP.GPIO_PuPd=GPIO_PULLDOWN diff --git a/Src/usb_device.c b/Src/usb_device.c index 300c3573..32dc5b7d 100644 --- a/Src/usb_device.c +++ b/Src/usb_device.c @@ -58,9 +58,13 @@ /* USB Device Core handle declaration */ USBD_HandleTypeDef hUsbDeviceFS; -/* init function */ +/* init function */ void MX_USB_DEVICE_Init(void) { + /* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */ + + /* USER CODE END USB_DEVICE_Init_PreTreatment */ + /* Init Device Library,Add Supported Class and Start the library*/ USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS); @@ -70,6 +74,9 @@ void MX_USB_DEVICE_Init(void) USBD_Start(&hUsbDeviceFS); + /* USER CODE BEGIN USB_DEVICE_Init_PostTreatment */ + + /* USER CODE END USB_DEVICE_Init_PostTreatment */ } /** * @} From c88639bf2947ac8b4c18d91d85cd9aa5c1a45a7f Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Tue, 10 Oct 2017 19:01:42 -0700 Subject: [PATCH 21/35] make TIM14 the HAL timebase --- Inc/stm32f4xx_hal_conf.h | 2 +- Inc/stm32f4xx_it.h | 1 + Makefile | 3 +- Odrive.ioc | 9 +- Src/main.c | 21 ++++ Src/stm32f4xx_hal_timebase_TIM.c | 158 +++++++++++++++++++++++++++++++ Src/stm32f4xx_it.c | 19 +++- Src/tim.c | 7 ++ 8 files changed, 214 insertions(+), 6 deletions(-) create mode 100644 Src/stm32f4xx_hal_timebase_TIM.c diff --git a/Inc/stm32f4xx_hal_conf.h b/Inc/stm32f4xx_hal_conf.h index 32073570..e94a4dc6 100644 --- a/Inc/stm32f4xx_hal_conf.h +++ b/Inc/stm32f4xx_hal_conf.h @@ -157,7 +157,7 @@ * @brief This is the HAL system configuration section */ #define VDD_VALUE ((uint32_t)3300U) /*!< Value of VDD in mv */ -#define TICK_INT_PRIORITY ((uint32_t)15U) /*!< tick interrupt priority */ +#define TICK_INT_PRIORITY ((uint32_t)0U) /*!< tick interrupt priority */ #define USE_RTOS 0U #define PREFETCH_ENABLE 1U #define INSTRUCTION_CACHE_ENABLE 1U diff --git a/Inc/stm32f4xx_it.h b/Inc/stm32f4xx_it.h index 56694aec..54400ebd 100644 --- a/Inc/stm32f4xx_it.h +++ b/Inc/stm32f4xx_it.h @@ -56,6 +56,7 @@ void DebugMon_Handler(void); void SysTick_Handler(void); void DMA1_Stream2_IRQHandler(void); void ADC_IRQHandler(void); +void TIM8_TRG_COM_TIM14_IRQHandler(void); void OTG_FS_IRQHandler(void); #ifdef __cplusplus diff --git a/Makefile b/Makefile index a852af35..4bb93535 100644 --- a/Makefile +++ b/Makefile @@ -42,13 +42,14 @@ C_SOURCES = \ Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c \ Src/system_stm32f4xx.c \ Src/stm32f4xx_it.c \ + Src/stm32f4xx_hal_msp.c \ + Src/stm32f4xx_hal_timebase_TIM.c \ Src/tim.c \ Src/gpio.c \ Src/main.c \ Src/adc.c \ Src/freertos.c \ Src/spi.c \ - Src/stm32f4xx_hal_msp.c \ Src/can.c \ Src/usart.c \ Src/dma.c \ diff --git a/Odrive.ioc b/Odrive.ioc index efda2c0c..fce679b2 100755 --- a/Odrive.ioc +++ b/Odrive.ioc @@ -167,7 +167,7 @@ Mcu.Pin49=PB8 Mcu.Pin5=PC0 Mcu.Pin50=PB9 Mcu.Pin51=VP_FREERTOS_VS_ENABLE -Mcu.Pin52=VP_SYS_VS_Systick +Mcu.Pin52=VP_SYS_VS_tim14 Mcu.Pin53=VP_TIM1_VS_ClockSourceINT Mcu.Pin54=VP_TIM1_VS_no_output4 Mcu.Pin55=VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS @@ -193,6 +193,9 @@ NVIC.PendSV_IRQn=true\:15\:0\:false\:false\:false\:true\:true NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:false\:false\:true NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:true\:true +NVIC.TIM8_TRG_COM_TIM14_IRQn=true\:0\:0\:false\:false\:true\:false\:false +NVIC.TimeBase=TIM8_TRG_COM_TIM14_IRQn +NVIC.TimeBaseIP=TIM14 NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:true PA0-WKUP.GPIOParameters=GPIO_PuPd,GPIO_Label PA0-WKUP.GPIO_Label=GPIO_1 @@ -591,8 +594,8 @@ USB_OTG_FS.VirtualMode=Device_Only USB_OTG_FS.vbus_sensing_enable=DISABLE VP_FREERTOS_VS_ENABLE.Mode=Enabled VP_FREERTOS_VS_ENABLE.Signal=FREERTOS_VS_ENABLE -VP_SYS_VS_Systick.Mode=SysTick -VP_SYS_VS_Systick.Signal=SYS_VS_Systick +VP_SYS_VS_tim14.Mode=TIM14 +VP_SYS_VS_tim14.Signal=SYS_VS_tim14 VP_TIM1_VS_ClockSourceINT.Mode=Internal VP_TIM1_VS_ClockSourceINT.Signal=TIM1_VS_ClockSourceINT VP_TIM1_VS_no_output4.Mode=Output Compare4 No Output diff --git a/Src/main.c b/Src/main.c index f773ff67..98a8beb9 100644 --- a/Src/main.c +++ b/Src/main.c @@ -208,6 +208,27 @@ void SystemClock_Config(void) /* USER CODE END 4 */ +/** + * @brief Period elapsed callback in non blocking mode + * @note This function is called when TIM14 interrupt took place, inside + * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment + * a global variable "uwTick" used as application time base. + * @param htim : TIM handle + * @retval None + */ +void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) +{ +/* USER CODE BEGIN Callback 0 */ + +/* USER CODE END Callback 0 */ + if (htim->Instance == TIM14) { + HAL_IncTick(); + } +/* USER CODE BEGIN Callback 1 */ + +/* USER CODE END Callback 1 */ +} + /** * @brief This function is executed in case of error occurrence. * @param None diff --git a/Src/stm32f4xx_hal_timebase_TIM.c b/Src/stm32f4xx_hal_timebase_TIM.c new file mode 100644 index 00000000..a74e4773 --- /dev/null +++ b/Src/stm32f4xx_hal_timebase_TIM.c @@ -0,0 +1,158 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_timebase_TIM.c + * @brief HAL time base based on the hardware TIM. + ****************************************************************************** + * This notice applies to any and all portions of this file + * that are not between comment pairs USER CODE BEGIN and + * USER CODE END. Other portions of this file, whether + * inserted by the user or by software development tools + * are owned by their respective copyright owners. + * + * Copyright (c) 2017 STMicroelectronics International N.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted, provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of other + * contributors to this software may be used to endorse or promote products + * derived from this software without specific written permission. + * 4. This software, including modifications and/or derivative works of this + * software, must execute solely and exclusively on microcontroller or + * microprocessor devices manufactured by or for STMicroelectronics. + * 5. Redistribution and use of this software other than as permitted under + * this license is void and will automatically terminate your rights under + * this license. + * + * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY + * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT + * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal.h" +#include "stm32f4xx_hal_tim.h" +/** @addtogroup STM32F7xx_HAL_Examples + * @{ + */ + +/** @addtogroup HAL_TimeBase + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +TIM_HandleTypeDef htim14; +uint32_t uwIncrementState = 0; +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** + * @brief This function configures the TIM14 as a time base source. + * The time source is configured to have 1ms time base with a dedicated + * Tick interrupt priority. + * @note This function is called automatically at the beginning of program after + * reset by HAL_Init() or at any time when clock is configured, by HAL_RCC_ClockConfig(). + * @param TickPriority: Tick interrupt priorty. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) +{ + RCC_ClkInitTypeDef clkconfig; + uint32_t uwTimclock = 0; + uint32_t uwPrescalerValue = 0; + uint32_t pFLatency; + + /*Configure the TIM14 IRQ priority */ + HAL_NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, TickPriority ,0); + + /* Enable the TIM14 global Interrupt */ + HAL_NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn); + + /* Enable TIM14 clock */ + __HAL_RCC_TIM14_CLK_ENABLE(); + + /* Get clock configuration */ + HAL_RCC_GetClockConfig(&clkconfig, &pFLatency); + + /* Compute TIM14 clock */ + uwTimclock = 2*HAL_RCC_GetPCLK1Freq(); + + /* Compute the prescaler value to have TIM14 counter clock equal to 1MHz */ + uwPrescalerValue = (uint32_t) ((uwTimclock / 1000000) - 1); + + /* Initialize TIM14 */ + htim14.Instance = TIM14; + + /* Initialize TIMx peripheral as follow: + + Period = [(TIM14CLK/1000) - 1]. to have a (1/1000) s time base. + + Prescaler = (uwTimclock/1000000 - 1) to have a 1MHz counter clock. + + ClockDivision = 0 + + Counter direction = Up + */ + htim14.Init.Period = (1000000 / 1000) - 1; + htim14.Init.Prescaler = uwPrescalerValue; + htim14.Init.ClockDivision = 0; + htim14.Init.CounterMode = TIM_COUNTERMODE_UP; + if(HAL_TIM_Base_Init(&htim14) == HAL_OK) + { + /* Start the TIM time Base generation in interrupt mode */ + return HAL_TIM_Base_Start_IT(&htim14); + } + + /* Return function status */ + return HAL_ERROR; +} + +/** + * @brief Suspend Tick increment. + * @note Disable the tick increment by disabling TIM14 update interrupt. + * @param None + * @retval None + */ +void HAL_SuspendTick(void) +{ + /* Disable TIM14 update Interrupt */ + __HAL_TIM_DISABLE_IT(&htim14, TIM_IT_UPDATE); +} + +/** + * @brief Resume Tick increment. + * @note Enable the tick increment by Enabling TIM14 update interrupt. + * @param None + * @retval None + */ +void HAL_ResumeTick(void) +{ + /* Enable TIM14 Update interrupt */ + __HAL_TIM_ENABLE_IT(&htim14, TIM_IT_UPDATE); +} + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/Src/stm32f4xx_it.c b/Src/stm32f4xx_it.c index 7c5c849e..cab050e4 100644 --- a/Src/stm32f4xx_it.c +++ b/Src/stm32f4xx_it.c @@ -54,8 +54,11 @@ extern PCD_HandleTypeDef hpcd_USB_OTG_FS; extern ADC_HandleTypeDef hadc1; extern ADC_HandleTypeDef hadc2; extern ADC_HandleTypeDef hadc3; +extern TIM_HandleTypeDef htim8; extern DMA_HandleTypeDef hdma_uart4_rx; +extern TIM_HandleTypeDef htim14; + /******************************************************************************/ /* Cortex-M4 Processor Interruption and Exception Handlers */ /******************************************************************************/ @@ -158,7 +161,6 @@ void SysTick_Handler(void) /* USER CODE BEGIN SysTick_IRQn 0 */ /* USER CODE END SysTick_IRQn 0 */ - HAL_IncTick(); osSystickHandler(); /* USER CODE BEGIN SysTick_IRQn 1 */ @@ -212,6 +214,21 @@ void ADC_IRQHandler(void) /* USER CODE END ADC_IRQn 1 */ } +/** +* @brief This function handles TIM8 trigger and commutation interrupts and TIM14 global interrupt. +*/ +void TIM8_TRG_COM_TIM14_IRQHandler(void) +{ + /* USER CODE BEGIN TIM8_TRG_COM_TIM14_IRQn 0 */ + + /* USER CODE END TIM8_TRG_COM_TIM14_IRQn 0 */ + HAL_TIM_IRQHandler(&htim8); + HAL_TIM_IRQHandler(&htim14); + /* USER CODE BEGIN TIM8_TRG_COM_TIM14_IRQn 1 */ + + /* USER CODE END TIM8_TRG_COM_TIM14_IRQn 1 */ +} + /** * @brief This function handles USB On The Go FS global interrupt. */ diff --git a/Src/tim.c b/Src/tim.c index 5131b240..300e4ae1 100644 --- a/Src/tim.c +++ b/Src/tim.c @@ -373,6 +373,10 @@ void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* tim_pwmHandle) /* USER CODE END TIM8_MspInit 0 */ /* TIM8 clock enable */ __HAL_RCC_TIM8_CLK_ENABLE(); + + /* TIM8 interrupt Init */ + HAL_NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn); /* USER CODE BEGIN TIM8_MspInit 1 */ /* USER CODE END TIM8_MspInit 1 */ @@ -565,6 +569,9 @@ void HAL_TIM_PWM_MspDeInit(TIM_HandleTypeDef* tim_pwmHandle) /* USER CODE END TIM8_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_TIM8_CLK_DISABLE(); + + /* TIM8 interrupt Deinit */ + HAL_NVIC_DisableIRQ(TIM8_TRG_COM_TIM14_IRQn); /* USER CODE BEGIN TIM8_MspDeInit 1 */ /* USER CODE END TIM8_MspDeInit 1 */ From 2f4015b3c05171a68646e703e219911a27693183 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sun, 1 Oct 2017 22:32:03 -0700 Subject: [PATCH 22/35] add vscode intellisense --- .vscode/c_cpp_properties.json | 4 +++- MotorControl/low_level.c | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index bd8d33ee..2fb3414a 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -15,7 +15,9 @@ "${workspaceRoot}/Drivers/CMSIS/Device/ST/STM32F4xx/Include", "${workspaceRoot}/Drivers/CMSIS/Include", "${workspaceRoot}/Inc", - "${workspaceRoot}/MotorControl" + "${workspaceRoot}/MotorControl", + "C:/Program Files (x86)/GNU Tools ARM Embedded/6 2017-q1-update/arm-none-eabi/include", + "C:/Program Files (x86)/GNU Tools ARM Embedded/6 2017-q1-update/lib/gcc/arm-none-eabi/6.3.1/include" ], "defines": [ "_DEBUG", diff --git a/MotorControl/low_level.c b/MotorControl/low_level.c index 1d1da1b6..a7cf7fa2 100755 --- a/MotorControl/low_level.c +++ b/MotorControl/low_level.c @@ -2,12 +2,14 @@ // Because of broken cmsis_os.h, we need to include arm_math first, // otherwise chip specific defines are ommited +#include #include // Sets up the correct chip specifc defines required by arm_math #define ARM_MATH_CM4 #include #include +#include #include #include #include From 41473f2bfb31d6e712b66b39c96774dd083a3c1c Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Tue, 10 Oct 2017 19:49:52 -0700 Subject: [PATCH 23/35] Turn on uart TX DMA --- .../Source/Templates/system_stm32f4xx.c | 763 ------------------ Inc/stm32f4xx_it.h | 1 + Odrive.ioc | 14 +- STM32F405RGTx_FLASH.ld | 33 +- Src/dma.c | 3 + Src/stm32f4xx_it.c | 15 + Src/usart.c | 20 + startup/startup_stm32f405xx.s | 6 +- 8 files changed, 62 insertions(+), 793 deletions(-) delete mode 100644 Drivers/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c diff --git a/Drivers/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c b/Drivers/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c deleted file mode 100644 index acfd44c3..00000000 --- a/Drivers/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c +++ /dev/null @@ -1,763 +0,0 @@ -/** - ****************************************************************************** - * @file system_stm32f4xx.c - * @author MCD Application Team - * @version V2.6.1 - * @date 14-February-2017 - * @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File. - * - * This file provides two functions and one global variable to be called from - * user application: - * - SystemInit(): This function is called at startup just after reset and - * before branch to main program. This call is made inside - * the "startup_stm32f4xx.s" file. - * - * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used - * by the user application to setup the SysTick - * timer or configure other parameters. - * - * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must - * be called whenever the core clock is changed - * during program execution. - * - * - ****************************************************************************** - * @attention - * - *

© COPYRIGHT 2017 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -/** @addtogroup CMSIS - * @{ - */ - -/** @addtogroup stm32f4xx_system - * @{ - */ - -/** @addtogroup STM32F4xx_System_Private_Includes - * @{ - */ - - -#include "stm32f4xx.h" - -#if !defined (HSE_VALUE) - #define HSE_VALUE ((uint32_t)25000000) /*!< Default value of the External oscillator in Hz */ -#endif /* HSE_VALUE */ - -#if !defined (HSI_VALUE) - #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ -#endif /* HSI_VALUE */ - -/** - * @} - */ - -/** @addtogroup STM32F4xx_System_Private_TypesDefinitions - * @{ - */ - -/** - * @} - */ - -/** @addtogroup STM32F4xx_System_Private_Defines - * @{ - */ - -/************************* Miscellaneous Configuration ************************/ -/*!< Uncomment the following line if you need to use external SRAM or SDRAM as data memory */ -#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx)\ - || defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\ - || defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F412Zx) || defined(STM32F412Vx) -/* #define DATA_IN_ExtSRAM */ -#endif /* STM32F40xxx || STM32F41xxx || STM32F42xxx || STM32F43xxx || STM32F469xx || STM32F479xx ||\ - STM32F412Zx || STM32F412Vx */ - -#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\ - || defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx) -/* #define DATA_IN_ExtSDRAM */ -#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F446xx || STM32F469xx ||\ - STM32F479xx */ - -/*!< Uncomment the following line if you need to relocate your vector Table in - Internal SRAM. */ -/* #define VECT_TAB_SRAM */ -#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field. - This value must be a multiple of 0x200. */ -/******************************************************************************/ - -/** - * @} - */ - -/** @addtogroup STM32F4xx_System_Private_Macros - * @{ - */ - -/** - * @} - */ - -/** @addtogroup STM32F4xx_System_Private_Variables - * @{ - */ - /* This variable is updated in three ways: - 1) by calling CMSIS function SystemCoreClockUpdate() - 2) by calling HAL API function HAL_RCC_GetHCLKFreq() - 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency - Note: If you use this function to configure the system clock; then there - is no need to call the 2 first functions listed above, since SystemCoreClock - variable is updated automatically. - */ -uint32_t SystemCoreClock = 16000000; -const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; -const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; -/** - * @} - */ - -/** @addtogroup STM32F4xx_System_Private_FunctionPrototypes - * @{ - */ - -#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM) - static void SystemInit_ExtMemCtl(void); -#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */ - -/** - * @} - */ - -/** @addtogroup STM32F4xx_System_Private_Functions - * @{ - */ - -/** - * @brief Setup the microcontroller system - * Initialize the FPU setting, vector table location and External memory - * configuration. - * @param None - * @retval None - */ -void SystemInit(void) -{ - /* FPU settings ------------------------------------------------------------*/ - #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) - SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */ - #endif - /* Reset the RCC clock configuration to the default reset state ------------*/ - /* Set HSION bit */ - RCC->CR |= (uint32_t)0x00000001; - - /* Reset CFGR register */ - RCC->CFGR = 0x00000000; - - /* Reset HSEON, CSSON and PLLON bits */ - RCC->CR &= (uint32_t)0xFEF6FFFF; - - /* Reset PLLCFGR register */ - RCC->PLLCFGR = 0x24003010; - - /* Reset HSEBYP bit */ - RCC->CR &= (uint32_t)0xFFFBFFFF; - - /* Disable all interrupts */ - RCC->CIR = 0x00000000; - -#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM) - SystemInit_ExtMemCtl(); -#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */ - - /* Configure the Vector Table location add offset address ------------------*/ -#ifdef VECT_TAB_SRAM - SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */ -#else - SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */ -#endif -} - -/** - * @brief Update SystemCoreClock variable according to Clock Register Values. - * The SystemCoreClock variable contains the core clock (HCLK), it can - * be used by the user application to setup the SysTick timer or configure - * other parameters. - * - * @note Each time the core clock (HCLK) changes, this function must be called - * to update SystemCoreClock variable value. Otherwise, any configuration - * based on this variable will be incorrect. - * - * @note - The system frequency computed by this function is not the real - * frequency in the chip. It is calculated based on the predefined - * constant and the selected clock source: - * - * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*) - * - * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**) - * - * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**) - * or HSI_VALUE(*) multiplied/divided by the PLL factors. - * - * (*) HSI_VALUE is a constant defined in stm32f4xx_hal_conf.h file (default value - * 16 MHz) but the real value may vary depending on the variations - * in voltage and temperature. - * - * (**) HSE_VALUE is a constant defined in stm32f4xx_hal_conf.h file (its value - * depends on the application requirements), user has to ensure that HSE_VALUE - * is same as the real frequency of the crystal used. Otherwise, this function - * may have wrong result. - * - * - The result of this function could be not correct when using fractional - * value for HSE crystal. - * - * @param None - * @retval None - */ -void SystemCoreClockUpdate(void) -{ - uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2; - - /* Get SYSCLK source -------------------------------------------------------*/ - tmp = RCC->CFGR & RCC_CFGR_SWS; - - switch (tmp) - { - case 0x00: /* HSI used as system clock source */ - SystemCoreClock = HSI_VALUE; - break; - case 0x04: /* HSE used as system clock source */ - SystemCoreClock = HSE_VALUE; - break; - case 0x08: /* PLL used as system clock source */ - - /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N - SYSCLK = PLL_VCO / PLL_P - */ - pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22; - pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM; - - if (pllsource != 0) - { - /* HSE used as PLL clock source */ - pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6); - } - else - { - /* HSI used as PLL clock source */ - pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6); - } - - pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2; - SystemCoreClock = pllvco/pllp; - break; - default: - SystemCoreClock = HSI_VALUE; - break; - } - /* Compute HCLK frequency --------------------------------------------------*/ - /* Get HCLK prescaler */ - tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)]; - /* HCLK frequency */ - SystemCoreClock >>= tmp; -} - -#if defined (DATA_IN_ExtSRAM) && defined (DATA_IN_ExtSDRAM) -#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\ - || defined(STM32F469xx) || defined(STM32F479xx) -/** - * @brief Setup the external memory controller. - * Called in startup_stm32f4xx.s before jump to main. - * This function configures the external memories (SRAM/SDRAM) - * This SRAM/SDRAM will be used as program data memory (including heap and stack). - * @param None - * @retval None - */ -void SystemInit_ExtMemCtl(void) -{ - __IO uint32_t tmp = 0x00; - - register uint32_t tmpreg = 0, timeout = 0xFFFF; - register __IO uint32_t index; - - /* Enable GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOH and GPIOI interface clock */ - RCC->AHB1ENR |= 0x000001F8; - - /* Delay after an RCC peripheral clock enabling */ - tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN); - - /* Connect PDx pins to FMC Alternate function */ - GPIOD->AFR[0] = 0x00CCC0CC; - GPIOD->AFR[1] = 0xCCCCCCCC; - /* Configure PDx pins in Alternate function mode */ - GPIOD->MODER = 0xAAAA0A8A; - /* Configure PDx pins speed to 100 MHz */ - GPIOD->OSPEEDR = 0xFFFF0FCF; - /* Configure PDx pins Output type to push-pull */ - GPIOD->OTYPER = 0x00000000; - /* No pull-up, pull-down for PDx pins */ - GPIOD->PUPDR = 0x00000000; - - /* Connect PEx pins to FMC Alternate function */ - GPIOE->AFR[0] = 0xC00CC0CC; - GPIOE->AFR[1] = 0xCCCCCCCC; - /* Configure PEx pins in Alternate function mode */ - GPIOE->MODER = 0xAAAA828A; - /* Configure PEx pins speed to 100 MHz */ - GPIOE->OSPEEDR = 0xFFFFC3CF; - /* Configure PEx pins Output type to push-pull */ - GPIOE->OTYPER = 0x00000000; - /* No pull-up, pull-down for PEx pins */ - GPIOE->PUPDR = 0x00000000; - - /* Connect PFx pins to FMC Alternate function */ - GPIOF->AFR[0] = 0xCCCCCCCC; - GPIOF->AFR[1] = 0xCCCCCCCC; - /* Configure PFx pins in Alternate function mode */ - GPIOF->MODER = 0xAA800AAA; - /* Configure PFx pins speed to 50 MHz */ - GPIOF->OSPEEDR = 0xAA800AAA; - /* Configure PFx pins Output type to push-pull */ - GPIOF->OTYPER = 0x00000000; - /* No pull-up, pull-down for PFx pins */ - GPIOF->PUPDR = 0x00000000; - - /* Connect PGx pins to FMC Alternate function */ - GPIOG->AFR[0] = 0xCCCCCCCC; - GPIOG->AFR[1] = 0xCCCCCCCC; - /* Configure PGx pins in Alternate function mode */ - GPIOG->MODER = 0xAAAAAAAA; - /* Configure PGx pins speed to 50 MHz */ - GPIOG->OSPEEDR = 0xAAAAAAAA; - /* Configure PGx pins Output type to push-pull */ - GPIOG->OTYPER = 0x00000000; - /* No pull-up, pull-down for PGx pins */ - GPIOG->PUPDR = 0x00000000; - - /* Connect PHx pins to FMC Alternate function */ - GPIOH->AFR[0] = 0x00C0CC00; - GPIOH->AFR[1] = 0xCCCCCCCC; - /* Configure PHx pins in Alternate function mode */ - GPIOH->MODER = 0xAAAA08A0; - /* Configure PHx pins speed to 50 MHz */ - GPIOH->OSPEEDR = 0xAAAA08A0; - /* Configure PHx pins Output type to push-pull */ - GPIOH->OTYPER = 0x00000000; - /* No pull-up, pull-down for PHx pins */ - GPIOH->PUPDR = 0x00000000; - - /* Connect PIx pins to FMC Alternate function */ - GPIOI->AFR[0] = 0xCCCCCCCC; - GPIOI->AFR[1] = 0x00000CC0; - /* Configure PIx pins in Alternate function mode */ - GPIOI->MODER = 0x0028AAAA; - /* Configure PIx pins speed to 50 MHz */ - GPIOI->OSPEEDR = 0x0028AAAA; - /* Configure PIx pins Output type to push-pull */ - GPIOI->OTYPER = 0x00000000; - /* No pull-up, pull-down for PIx pins */ - GPIOI->PUPDR = 0x00000000; - -/*-- FMC Configuration -------------------------------------------------------*/ - /* Enable the FMC interface clock */ - RCC->AHB3ENR |= 0x00000001; - /* Delay after an RCC peripheral clock enabling */ - tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN); - - FMC_Bank5_6->SDCR[0] = 0x000019E4; - FMC_Bank5_6->SDTR[0] = 0x01115351; - - /* SDRAM initialization sequence */ - /* Clock enable command */ - FMC_Bank5_6->SDCMR = 0x00000011; - tmpreg = FMC_Bank5_6->SDSR & 0x00000020; - while((tmpreg != 0) && (timeout-- > 0)) - { - tmpreg = FMC_Bank5_6->SDSR & 0x00000020; - } - - /* Delay */ - for (index = 0; index<1000; index++); - - /* PALL command */ - FMC_Bank5_6->SDCMR = 0x00000012; - timeout = 0xFFFF; - while((tmpreg != 0) && (timeout-- > 0)) - { - tmpreg = FMC_Bank5_6->SDSR & 0x00000020; - } - - /* Auto refresh command */ - FMC_Bank5_6->SDCMR = 0x00000073; - timeout = 0xFFFF; - while((tmpreg != 0) && (timeout-- > 0)) - { - tmpreg = FMC_Bank5_6->SDSR & 0x00000020; - } - - /* MRD register program */ - FMC_Bank5_6->SDCMR = 0x00046014; - timeout = 0xFFFF; - while((tmpreg != 0) && (timeout-- > 0)) - { - tmpreg = FMC_Bank5_6->SDSR & 0x00000020; - } - - /* Set refresh count */ - tmpreg = FMC_Bank5_6->SDRTR; - FMC_Bank5_6->SDRTR = (tmpreg | (0x0000027C<<1)); - - /* Disable write protection */ - tmpreg = FMC_Bank5_6->SDCR[0]; - FMC_Bank5_6->SDCR[0] = (tmpreg & 0xFFFFFDFF); - -#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) - /* Configure and enable Bank1_SRAM2 */ - FMC_Bank1->BTCR[2] = 0x00001011; - FMC_Bank1->BTCR[3] = 0x00000201; - FMC_Bank1E->BWTR[2] = 0x0fffffff; -#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx */ -#if defined(STM32F469xx) || defined(STM32F479xx) - /* Configure and enable Bank1_SRAM2 */ - FMC_Bank1->BTCR[2] = 0x00001091; - FMC_Bank1->BTCR[3] = 0x00110212; - FMC_Bank1E->BWTR[2] = 0x0fffffff; -#endif /* STM32F469xx || STM32F479xx */ - - (void)(tmp); -} -#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx */ -#elif defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM) -/** - * @brief Setup the external memory controller. - * Called in startup_stm32f4xx.s before jump to main. - * This function configures the external memories (SRAM/SDRAM) - * This SRAM/SDRAM will be used as program data memory (including heap and stack). - * @param None - * @retval None - */ -void SystemInit_ExtMemCtl(void) -{ - __IO uint32_t tmp = 0x00; -#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\ - || defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx) -#if defined (DATA_IN_ExtSDRAM) - register uint32_t tmpreg = 0, timeout = 0xFFFF; - register __IO uint32_t index; - -#if defined(STM32F446xx) - /* Enable GPIOA, GPIOC, GPIOD, GPIOE, GPIOF, GPIOG interface - clock */ - RCC->AHB1ENR |= 0x0000007D; -#else - /* Enable GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOH and GPIOI interface - clock */ - RCC->AHB1ENR |= 0x000001F8; -#endif /* STM32F446xx */ - /* Delay after an RCC peripheral clock enabling */ - tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN); - -#if defined(STM32F446xx) - /* Connect PAx pins to FMC Alternate function */ - GPIOA->AFR[0] |= 0xC0000000; - GPIOA->AFR[1] |= 0x00000000; - /* Configure PDx pins in Alternate function mode */ - GPIOA->MODER |= 0x00008000; - /* Configure PDx pins speed to 50 MHz */ - GPIOA->OSPEEDR |= 0x00008000; - /* Configure PDx pins Output type to push-pull */ - GPIOA->OTYPER |= 0x00000000; - /* No pull-up, pull-down for PDx pins */ - GPIOA->PUPDR |= 0x00000000; - - /* Connect PCx pins to FMC Alternate function */ - GPIOC->AFR[0] |= 0x00CC0000; - GPIOC->AFR[1] |= 0x00000000; - /* Configure PDx pins in Alternate function mode */ - GPIOC->MODER |= 0x00000A00; - /* Configure PDx pins speed to 50 MHz */ - GPIOC->OSPEEDR |= 0x00000A00; - /* Configure PDx pins Output type to push-pull */ - GPIOC->OTYPER |= 0x00000000; - /* No pull-up, pull-down for PDx pins */ - GPIOC->PUPDR |= 0x00000000; -#endif /* STM32F446xx */ - - /* Connect PDx pins to FMC Alternate function */ - GPIOD->AFR[0] = 0x000000CC; - GPIOD->AFR[1] = 0xCC000CCC; - /* Configure PDx pins in Alternate function mode */ - GPIOD->MODER = 0xA02A000A; - /* Configure PDx pins speed to 50 MHz */ - GPIOD->OSPEEDR = 0xA02A000A; - /* Configure PDx pins Output type to push-pull */ - GPIOD->OTYPER = 0x00000000; - /* No pull-up, pull-down for PDx pins */ - GPIOD->PUPDR = 0x00000000; - - /* Connect PEx pins to FMC Alternate function */ - GPIOE->AFR[0] = 0xC00000CC; - GPIOE->AFR[1] = 0xCCCCCCCC; - /* Configure PEx pins in Alternate function mode */ - GPIOE->MODER = 0xAAAA800A; - /* Configure PEx pins speed to 50 MHz */ - GPIOE->OSPEEDR = 0xAAAA800A; - /* Configure PEx pins Output type to push-pull */ - GPIOE->OTYPER = 0x00000000; - /* No pull-up, pull-down for PEx pins */ - GPIOE->PUPDR = 0x00000000; - - /* Connect PFx pins to FMC Alternate function */ - GPIOF->AFR[0] = 0xCCCCCCCC; - GPIOF->AFR[1] = 0xCCCCCCCC; - /* Configure PFx pins in Alternate function mode */ - GPIOF->MODER = 0xAA800AAA; - /* Configure PFx pins speed to 50 MHz */ - GPIOF->OSPEEDR = 0xAA800AAA; - /* Configure PFx pins Output type to push-pull */ - GPIOF->OTYPER = 0x00000000; - /* No pull-up, pull-down for PFx pins */ - GPIOF->PUPDR = 0x00000000; - - /* Connect PGx pins to FMC Alternate function */ - GPIOG->AFR[0] = 0xCCCCCCCC; - GPIOG->AFR[1] = 0xCCCCCCCC; - /* Configure PGx pins in Alternate function mode */ - GPIOG->MODER = 0xAAAAAAAA; - /* Configure PGx pins speed to 50 MHz */ - GPIOG->OSPEEDR = 0xAAAAAAAA; - /* Configure PGx pins Output type to push-pull */ - GPIOG->OTYPER = 0x00000000; - /* No pull-up, pull-down for PGx pins */ - GPIOG->PUPDR = 0x00000000; - -#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\ - || defined(STM32F469xx) || defined(STM32F479xx) - /* Connect PHx pins to FMC Alternate function */ - GPIOH->AFR[0] = 0x00C0CC00; - GPIOH->AFR[1] = 0xCCCCCCCC; - /* Configure PHx pins in Alternate function mode */ - GPIOH->MODER = 0xAAAA08A0; - /* Configure PHx pins speed to 50 MHz */ - GPIOH->OSPEEDR = 0xAAAA08A0; - /* Configure PHx pins Output type to push-pull */ - GPIOH->OTYPER = 0x00000000; - /* No pull-up, pull-down for PHx pins */ - GPIOH->PUPDR = 0x00000000; - - /* Connect PIx pins to FMC Alternate function */ - GPIOI->AFR[0] = 0xCCCCCCCC; - GPIOI->AFR[1] = 0x00000CC0; - /* Configure PIx pins in Alternate function mode */ - GPIOI->MODER = 0x0028AAAA; - /* Configure PIx pins speed to 50 MHz */ - GPIOI->OSPEEDR = 0x0028AAAA; - /* Configure PIx pins Output type to push-pull */ - GPIOI->OTYPER = 0x00000000; - /* No pull-up, pull-down for PIx pins */ - GPIOI->PUPDR = 0x00000000; -#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx */ - -/*-- FMC Configuration -------------------------------------------------------*/ - /* Enable the FMC interface clock */ - RCC->AHB3ENR |= 0x00000001; - /* Delay after an RCC peripheral clock enabling */ - tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN); - - /* Configure and enable SDRAM bank1 */ -#if defined(STM32F446xx) - FMC_Bank5_6->SDCR[0] = 0x00001954; -#else - FMC_Bank5_6->SDCR[0] = 0x000019E4; -#endif /* STM32F446xx */ - FMC_Bank5_6->SDTR[0] = 0x01115351; - - /* SDRAM initialization sequence */ - /* Clock enable command */ - FMC_Bank5_6->SDCMR = 0x00000011; - tmpreg = FMC_Bank5_6->SDSR & 0x00000020; - while((tmpreg != 0) && (timeout-- > 0)) - { - tmpreg = FMC_Bank5_6->SDSR & 0x00000020; - } - - /* Delay */ - for (index = 0; index<1000; index++); - - /* PALL command */ - FMC_Bank5_6->SDCMR = 0x00000012; - timeout = 0xFFFF; - while((tmpreg != 0) && (timeout-- > 0)) - { - tmpreg = FMC_Bank5_6->SDSR & 0x00000020; - } - - /* Auto refresh command */ -#if defined(STM32F446xx) - FMC_Bank5_6->SDCMR = 0x000000F3; -#else - FMC_Bank5_6->SDCMR = 0x00000073; -#endif /* STM32F446xx */ - timeout = 0xFFFF; - while((tmpreg != 0) && (timeout-- > 0)) - { - tmpreg = FMC_Bank5_6->SDSR & 0x00000020; - } - - /* MRD register program */ -#if defined(STM32F446xx) - FMC_Bank5_6->SDCMR = 0x00044014; -#else - FMC_Bank5_6->SDCMR = 0x00046014; -#endif /* STM32F446xx */ - timeout = 0xFFFF; - while((tmpreg != 0) && (timeout-- > 0)) - { - tmpreg = FMC_Bank5_6->SDSR & 0x00000020; - } - - /* Set refresh count */ - tmpreg = FMC_Bank5_6->SDRTR; -#if defined(STM32F446xx) - FMC_Bank5_6->SDRTR = (tmpreg | (0x0000050C<<1)); -#else - FMC_Bank5_6->SDRTR = (tmpreg | (0x0000027C<<1)); -#endif /* STM32F446xx */ - - /* Disable write protection */ - tmpreg = FMC_Bank5_6->SDCR[0]; - FMC_Bank5_6->SDCR[0] = (tmpreg & 0xFFFFFDFF); -#endif /* DATA_IN_ExtSDRAM */ -#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F446xx || STM32F469xx || STM32F479xx */ - -#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx)\ - || defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\ - || defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F412Zx) || defined(STM32F412Vx) - -#if defined(DATA_IN_ExtSRAM) -/*-- GPIOs Configuration -----------------------------------------------------*/ - /* Enable GPIOD, GPIOE, GPIOF and GPIOG interface clock */ - RCC->AHB1ENR |= 0x00000078; - /* Delay after an RCC peripheral clock enabling */ - tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIODEN); - - /* Connect PDx pins to FMC Alternate function */ - GPIOD->AFR[0] = 0x00CCC0CC; - GPIOD->AFR[1] = 0xCCCCCCCC; - /* Configure PDx pins in Alternate function mode */ - GPIOD->MODER = 0xAAAA0A8A; - /* Configure PDx pins speed to 100 MHz */ - GPIOD->OSPEEDR = 0xFFFF0FCF; - /* Configure PDx pins Output type to push-pull */ - GPIOD->OTYPER = 0x00000000; - /* No pull-up, pull-down for PDx pins */ - GPIOD->PUPDR = 0x00000000; - - /* Connect PEx pins to FMC Alternate function */ - GPIOE->AFR[0] = 0xC00CC0CC; - GPIOE->AFR[1] = 0xCCCCCCCC; - /* Configure PEx pins in Alternate function mode */ - GPIOE->MODER = 0xAAAA828A; - /* Configure PEx pins speed to 100 MHz */ - GPIOE->OSPEEDR = 0xFFFFC3CF; - /* Configure PEx pins Output type to push-pull */ - GPIOE->OTYPER = 0x00000000; - /* No pull-up, pull-down for PEx pins */ - GPIOE->PUPDR = 0x00000000; - - /* Connect PFx pins to FMC Alternate function */ - GPIOF->AFR[0] = 0x00CCCCCC; - GPIOF->AFR[1] = 0xCCCC0000; - /* Configure PFx pins in Alternate function mode */ - GPIOF->MODER = 0xAA000AAA; - /* Configure PFx pins speed to 100 MHz */ - GPIOF->OSPEEDR = 0xFF000FFF; - /* Configure PFx pins Output type to push-pull */ - GPIOF->OTYPER = 0x00000000; - /* No pull-up, pull-down for PFx pins */ - GPIOF->PUPDR = 0x00000000; - - /* Connect PGx pins to FMC Alternate function */ - GPIOG->AFR[0] = 0x00CCCCCC; - GPIOG->AFR[1] = 0x000000C0; - /* Configure PGx pins in Alternate function mode */ - GPIOG->MODER = 0x00085AAA; - /* Configure PGx pins speed to 100 MHz */ - GPIOG->OSPEEDR = 0x000CAFFF; - /* Configure PGx pins Output type to push-pull */ - GPIOG->OTYPER = 0x00000000; - /* No pull-up, pull-down for PGx pins */ - GPIOG->PUPDR = 0x00000000; - -/*-- FMC/FSMC Configuration --------------------------------------------------*/ - /* Enable the FMC/FSMC interface clock */ - RCC->AHB3ENR |= 0x00000001; - -#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) - /* Delay after an RCC peripheral clock enabling */ - tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN); - /* Configure and enable Bank1_SRAM2 */ - FMC_Bank1->BTCR[2] = 0x00001011; - FMC_Bank1->BTCR[3] = 0x00000201; - FMC_Bank1E->BWTR[2] = 0x0fffffff; -#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx */ -#if defined(STM32F469xx) || defined(STM32F479xx) - /* Delay after an RCC peripheral clock enabling */ - tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN); - /* Configure and enable Bank1_SRAM2 */ - FMC_Bank1->BTCR[2] = 0x00001091; - FMC_Bank1->BTCR[3] = 0x00110212; - FMC_Bank1E->BWTR[2] = 0x0fffffff; -#endif /* STM32F469xx || STM32F479xx */ -#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx)|| defined(STM32F417xx)\ - || defined(STM32F412Zx) || defined(STM32F412Vx) - /* Delay after an RCC peripheral clock enabling */ - tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FSMCEN); - /* Configure and enable Bank1_SRAM2 */ - FSMC_Bank1->BTCR[2] = 0x00001011; - FSMC_Bank1->BTCR[3] = 0x00000201; - FSMC_Bank1E->BWTR[2] = 0x0FFFFFFF; -#endif /* STM32F405xx || STM32F415xx || STM32F407xx || STM32F417xx || STM32F412Zx || STM32F412Vx */ - -#endif /* DATA_IN_ExtSRAM */ -#endif /* STM32F405xx || STM32F415xx || STM32F407xx || STM32F417xx || STM32F427xx || STM32F437xx ||\ - STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx || STM32F412Zx || STM32F412Vx */ - (void)(tmp); -} -#endif /* DATA_IN_ExtSRAM && DATA_IN_ExtSDRAM */ -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/Inc/stm32f4xx_it.h b/Inc/stm32f4xx_it.h index 54400ebd..8fcd22cf 100644 --- a/Inc/stm32f4xx_it.h +++ b/Inc/stm32f4xx_it.h @@ -55,6 +55,7 @@ void UsageFault_Handler(void); void DebugMon_Handler(void); void SysTick_Handler(void); void DMA1_Stream2_IRQHandler(void); +void DMA1_Stream4_IRQHandler(void); void ADC_IRQHandler(void); void TIM8_TRG_COM_TIM14_IRQHandler(void); void OTG_FS_IRQHandler(void); diff --git a/Odrive.ioc b/Odrive.ioc index fce679b2..1c222c69 100755 --- a/Odrive.ioc +++ b/Odrive.ioc @@ -81,7 +81,8 @@ CAN1.CalculateTimeBit=1142 CAN1.CalculateTimeQuantum=380.95238095238096 CAN1.IPParameters=CalculateTimeQuantum,CalculateTimeBit,BS1,BS2 Dma.Request0=UART4_RX -Dma.RequestsNb=1 +Dma.Request1=UART4_TX +Dma.RequestsNb=2 Dma.UART4_RX.0.Direction=DMA_PERIPH_TO_MEMORY Dma.UART4_RX.0.FIFOMode=DMA_FIFOMODE_DISABLE Dma.UART4_RX.0.Instance=DMA1_Stream2 @@ -92,6 +93,16 @@ Dma.UART4_RX.0.PeriphDataAlignment=DMA_PDATAALIGN_BYTE Dma.UART4_RX.0.PeriphInc=DMA_PINC_DISABLE Dma.UART4_RX.0.Priority=DMA_PRIORITY_LOW Dma.UART4_RX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +Dma.UART4_TX.1.Direction=DMA_MEMORY_TO_PERIPH +Dma.UART4_TX.1.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.UART4_TX.1.Instance=DMA1_Stream4 +Dma.UART4_TX.1.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.UART4_TX.1.MemInc=DMA_MINC_ENABLE +Dma.UART4_TX.1.Mode=DMA_NORMAL +Dma.UART4_TX.1.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.UART4_TX.1.PeriphInc=DMA_PINC_DISABLE +Dma.UART4_TX.1.Priority=DMA_PRIORITY_LOW +Dma.UART4_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode FREERTOS.INCLUDE_vTaskDelayUntil=1 FREERTOS.IPParameters=Tasks01,INCLUDE_vTaskDelayUntil FREERTOS.Tasks01=defaultTask,-3,256,StartDefaultTask,Default @@ -183,6 +194,7 @@ MxDb.Version=DB.4.0.221 NVIC.ADC_IRQn=true\:5\:0\:false\:false\:true\:true\:true NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:true NVIC.DMA1_Stream2_IRQn=true\:5\:0\:false\:false\:true\:true\:true +NVIC.DMA1_Stream4_IRQn=true\:5\:0\:false\:false\:true\:true\:false NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:true NVIC.EXTI2_IRQn=true\:0\:0\:false\:false\:false\:false\:true NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:true diff --git a/STM32F405RGTx_FLASH.ld b/STM32F405RGTx_FLASH.ld index a6acde7c..2598776f 100644 --- a/STM32F405RGTx_FLASH.ld +++ b/STM32F405RGTx_FLASH.ld @@ -18,32 +18,13 @@ ** Distribution: The file is distributed as is, without any warranty ** of any kind. ** -***************************************************************************** -** @attention -** -**

© COPYRIGHT(c) 2014 Ac6

-** -** Redistribution and use in source and binary forms, with or without modification, -** are permitted provided that the following conditions are met: -** 1. Redistributions of source code must retain the above copyright notice, -** this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright notice, -** this list of conditions and the following disclaimer in the documentation -** and/or other materials provided with the distribution. -** 3. Neither the name of Ac6 nor the names of its contributors -** may be used to endorse or promote products derived from this software -** without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** (c)Copyright Ac6. +** You may use this file as-is or modify it according to the needs of your +** project. Distribution of this file (unmodified or modified) is not +** permitted. Ac6 permit registered System Workbench for MCU users the +** rights to distribute the assembled, compiled & linked contents of this +** file as part of an application binary file, provided that it is built +** using the System Workbench for MCU toolchain. ** ***************************************************************************** */ diff --git a/Src/dma.c b/Src/dma.c index 615d014d..322d04ab 100644 --- a/Src/dma.c +++ b/Src/dma.c @@ -73,6 +73,9 @@ void MX_DMA_Init(void) /* DMA1_Stream2_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA1_Stream2_IRQn, 5, 0); HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn); + /* DMA1_Stream4_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn); } diff --git a/Src/stm32f4xx_it.c b/Src/stm32f4xx_it.c index cab050e4..2c3da6a4 100644 --- a/Src/stm32f4xx_it.c +++ b/Src/stm32f4xx_it.c @@ -56,6 +56,7 @@ extern ADC_HandleTypeDef hadc2; extern ADC_HandleTypeDef hadc3; extern TIM_HandleTypeDef htim8; extern DMA_HandleTypeDef hdma_uart4_rx; +extern DMA_HandleTypeDef hdma_uart4_tx; extern TIM_HandleTypeDef htim14; @@ -188,6 +189,20 @@ void DMA1_Stream2_IRQHandler(void) /* USER CODE END DMA1_Stream2_IRQn 1 */ } +/** +* @brief This function handles DMA1 stream4 global interrupt. +*/ +void DMA1_Stream4_IRQHandler(void) +{ + /* USER CODE BEGIN DMA1_Stream4_IRQn 0 */ + + /* USER CODE END DMA1_Stream4_IRQn 0 */ + HAL_DMA_IRQHandler(&hdma_uart4_tx); + /* USER CODE BEGIN DMA1_Stream4_IRQn 1 */ + + /* USER CODE END DMA1_Stream4_IRQn 1 */ +} + /** * @brief This function handles ADC1, ADC2 and ADC3 global interrupts. */ diff --git a/Src/usart.c b/Src/usart.c index a0842cf9..58182d39 100644 --- a/Src/usart.c +++ b/Src/usart.c @@ -59,6 +59,7 @@ UART_HandleTypeDef huart4; DMA_HandleTypeDef hdma_uart4_rx; +DMA_HandleTypeDef hdma_uart4_tx; /* UART4 init function */ void MX_UART4_Init(void) @@ -128,6 +129,24 @@ void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) __HAL_LINKDMA(uartHandle,hdmarx,hdma_uart4_rx); + /* UART4_TX Init */ + hdma_uart4_tx.Instance = DMA1_Stream4; + hdma_uart4_tx.Init.Channel = DMA_CHANNEL_4; + hdma_uart4_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_uart4_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_uart4_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_uart4_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_uart4_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_uart4_tx.Init.Mode = DMA_NORMAL; + hdma_uart4_tx.Init.Priority = DMA_PRIORITY_LOW; + hdma_uart4_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + if (HAL_DMA_Init(&hdma_uart4_tx) != HAL_OK) + { + _Error_Handler(__FILE__, __LINE__); + } + + __HAL_LINKDMA(uartHandle,hdmatx,hdma_uart4_tx); + /* USER CODE BEGIN UART4_MspInit 1 */ /* USER CODE END UART4_MspInit 1 */ @@ -153,6 +172,7 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle) /* UART4 DMA DeInit */ HAL_DMA_DeInit(uartHandle->hdmarx); + HAL_DMA_DeInit(uartHandle->hdmatx); /* USER CODE BEGIN UART4_MspDeInit 1 */ /* USER CODE END UART4_MspDeInit 1 */ diff --git a/startup/startup_stm32f405xx.s b/startup/startup_stm32f405xx.s index 21c91899..54fc98a0 100644 --- a/startup/startup_stm32f405xx.s +++ b/startup/startup_stm32f405xx.s @@ -2,8 +2,8 @@ ****************************************************************************** * @file startup_stm32f405xx.s * @author MCD Application Team - * @version V2.6.0 - * @date 04-November-2016 + * @version V2.6.1 + * @date 14-February-2017 * @brief STM32F405xx Devices vector table for GCC based toolchains. * This module performs: * - Set the initial SP @@ -16,7 +16,7 @@ ****************************************************************************** * @attention * - *

© COPYRIGHT 2016 STMicroelectronics

+ *

© COPYRIGHT 2017 STMicroelectronics

* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: From 19893ee0c057daa405b8fa99ffddc2bda86c3d8e Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Tue, 10 Oct 2017 20:36:07 -0700 Subject: [PATCH 24/35] Move command parsing to own file --- Makefile | 3 +- MotorControl/commands.c | 314 +++++++++++++++++++++++++++++++++++++++ MotorControl/commands.h | 10 ++ MotorControl/low_level.c | 232 ++--------------------------- MotorControl/low_level.h | 10 +- Src/freertos.c | 88 +---------- Src/syscalls.c | 1 + Src/usbd_cdc_if.c | 2 +- 8 files changed, 346 insertions(+), 314 deletions(-) create mode 100644 MotorControl/commands.c create mode 100644 MotorControl/commands.h diff --git a/Makefile b/Makefile index 4bb93535..2b6fa749 100644 --- a/Makefile +++ b/Makefile @@ -82,7 +82,8 @@ C_SOURCES = \ Src/usbd_cdc_if.c \ Src/syscalls.c \ MotorControl/utils.c \ - MotorControl/low_level.c + MotorControl/commands.c \ + MotorControl/low_level.c ASM_SOURCES = \ startup/startup_stm32f405xx.s diff --git a/MotorControl/commands.c b/MotorControl/commands.c new file mode 100644 index 00000000..8674a256 --- /dev/null +++ b/MotorControl/commands.c @@ -0,0 +1,314 @@ +/* Includes ------------------------------------------------------------------*/ +#include +#include +#include + +/* Private macros ------------------------------------------------------------*/ +/* Private typedef -----------------------------------------------------------*/ +/* Global constant data ------------------------------------------------------*/ +/* Global variables ----------------------------------------------------------*/ +extern PCD_HandleTypeDef hpcd_USB_OTG_FS; +/* Private constant data -----------------------------------------------------*/ +// variables exposed to usb/serial interface via set/get/monitor +// Note: this will be depricated soon +static float* const exposed_floats[] = { + &vbus_voltage, // ro + NULL, //&elec_rad_per_enc, // ro + &motors[0].pos_setpoint, // rw + &motors[0].pos_gain, // rw + &motors[0].vel_setpoint, // rw + &motors[0].vel_gain, // rw + &motors[0].vel_integrator_gain, // rw + &motors[0].vel_integrator_current, // rw + &motors[0].vel_limit, // rw + &motors[0].current_setpoint, // rw + &motors[0].calibration_current, // rw + &motors[0].phase_inductance, // ro + &motors[0].phase_resistance, // ro + &motors[0].current_meas.phB, // ro + &motors[0].current_meas.phC, // ro + &motors[0].DC_calib.phB, // rw + &motors[0].DC_calib.phC, // rw + &motors[0].shunt_conductance, // rw + &motors[0].phase_current_rev_gain, // rw + &motors[0].current_control.current_lim, // rw + &motors[0].current_control.p_gain, // rw + &motors[0].current_control.i_gain, // rw + &motors[0].current_control.v_current_control_integral_d, // rw + &motors[0].current_control.v_current_control_integral_q, // rw + &motors[0].current_control.Ibus, // ro + &motors[0].encoder.phase, // ro + &motors[0].encoder.pll_pos, // rw + &motors[0].encoder.pll_vel, // rw + &motors[0].encoder.pll_kp, // rw + &motors[0].encoder.pll_ki, // rw + &motors[1].pos_setpoint, // rw + &motors[1].pos_gain, // rw + &motors[1].vel_setpoint, // rw + &motors[1].vel_gain, // rw + &motors[1].vel_integrator_gain, // rw + &motors[1].vel_integrator_current, // rw + &motors[1].vel_limit, // rw + &motors[1].current_setpoint, // rw + &motors[1].calibration_current, // rw + &motors[1].phase_inductance, // ro + &motors[1].phase_resistance, // ro + &motors[1].current_meas.phB, // ro + &motors[1].current_meas.phC, // ro + &motors[1].DC_calib.phB, // rw + &motors[1].DC_calib.phC, // rw + &motors[1].shunt_conductance, // rw + &motors[1].phase_current_rev_gain, // rw + &motors[1].current_control.current_lim, // rw + &motors[1].current_control.p_gain, // rw + &motors[1].current_control.i_gain, // rw + &motors[1].current_control.v_current_control_integral_d, // rw + &motors[1].current_control.v_current_control_integral_q, // rw + &motors[1].current_control.Ibus, // ro + &motors[1].encoder.phase, // ro + &motors[1].encoder.pll_pos, // rw + &motors[1].encoder.pll_vel, // rw + &motors[1].encoder.pll_kp, // rw + &motors[1].encoder.pll_ki, // rw +}; + +static int* const exposed_ints[] = { + (int*)&motors[0].control_mode, // rw + &motors[0].encoder.encoder_offset, // rw + &motors[0].encoder.encoder_state, // ro + &motors[0].error, // rw + (int*)&motors[1].control_mode, // rw + &motors[1].encoder.encoder_offset, // rw + &motors[1].encoder.encoder_state, // ro + &motors[1].error, // rw +}; + +static bool* const exposed_bools[] = { + &motors[0].thread_ready, // ro + &motors[0].enable_control, // rw + &motors[0].do_calibration, // rw + &motors[0].calibration_ok, // ro + &motors[1].thread_ready, // ro + &motors[1].enable_control, // rw + &motors[1].do_calibration, // rw + &motors[1].calibration_ok, // ro +}; + +static uint16_t* const exposed_uint16[] = { + &motors[0].control_deadline, // rw + &motors[0].last_cpu_time, // ro + &motors[1].control_deadline, // rw + &motors[1].last_cpu_time, // ro +}; + +/* Private variables ---------------------------------------------------------*/ +monitoring_slot monitoring_slots[20] = {0}; +/* Private function prototypes -----------------------------------------------*/ +static void print_monitoring(int limit); + +/* Function implementations --------------------------------------------------*/ +void motor_parse_cmd(uint8_t* buffer, int len) { + // TODO very hacky way of terminating sscanf at end of buffer: + // We should do some proper struct packing instead of using sscanf altogether + buffer[len] = 0; + + // check incoming packet type + if (buffer[0] == 'p') { + // position control + unsigned motor_number; + float pos_setpoint, vel_feed_forward, current_feed_forward; + int numscan = sscanf((const char*)buffer, "p %u %f %f %f", &motor_number, &pos_setpoint, &vel_feed_forward, ¤t_feed_forward); + if (numscan == 4 && motor_number < num_motors) { + set_pos_setpoint(&motors[motor_number], pos_setpoint, vel_feed_forward, current_feed_forward); + } + } else if (buffer[0] == 'v') { + // velocity control + unsigned motor_number; + float vel_feed_forward, current_feed_forward; + int numscan = sscanf((const char*)buffer, "v %u %f %f", &motor_number, &vel_feed_forward, ¤t_feed_forward); + if (numscan == 3 && motor_number < num_motors) { + set_vel_setpoint(&motors[motor_number], vel_feed_forward, current_feed_forward); + } + } else if (buffer[0] == 'c') { + // current control + unsigned motor_number; + float current_feed_forward; + int numscan = sscanf((const char*)buffer, "c %u %f", &motor_number, ¤t_feed_forward); + if (numscan == 2 && motor_number < num_motors) { + set_current_setpoint(&motors[motor_number], current_feed_forward); + } + } else if (buffer[0] == 'g') { // GET + // g <0:float,1:int,2:bool,3:uint16> index + int type = 0; + int index = 0; + int numscan = sscanf((const char*)buffer, "g %u %u", &type, &index); + if (numscan == 2) { + switch(type){ + case 0: { + printf("%f\n",*exposed_floats[index]); + break; + }; + case 1: { + printf("%d\n",*exposed_ints[index]); + break; + }; + case 2: { + printf("%d\n",*exposed_bools[index]); + break; + }; + case 3: { + printf("%hu\n",*exposed_uint16[index]); + break; + }; + } + } + } else if (buffer[0] == 's') { // SET + // s <0:float,1:int,2:bool,3:uint16> index value + int type = 0; + int index = 0; + int numscan = sscanf((const char*)buffer, "s %u %u", &type, &index); + if (numscan == 2) { + switch(type) { + case 0: { + sscanf((const char*)buffer, "s %u %u %f", &type, &index, exposed_floats[index]); + break; + }; + case 1: { + sscanf((const char*)buffer, "s %u %u %d", &type, &index, exposed_ints[index]); + break; + }; + case 2: { + int btmp = 0; + sscanf((const char*)buffer, "s %u %u %d", &type, &index, &btmp); + *exposed_bools[index] = btmp ? true : false; + break; + }; + case 3: { + sscanf((const char*)buffer, "s %u %u %hu", &type, &index, exposed_uint16[index]); + break; + }; + } + } + } else if (buffer[0] == 'm') { // Setup Monitor + // m <0:float,1:int,2:bool,3:uint16> index monitoring_slot + int type = 0; + int index = 0; + int slot = 0; + int numscan = sscanf((const char*)buffer, "m %u %u %u", &type, &index, &slot); + if (numscan == 3) { + monitoring_slots[slot].type = type; + monitoring_slots[slot].index = index; + } + } else if (buffer[0] == 'o') { // Output Monitor + int limit = 0; + int numscan = sscanf((const char*)buffer, "o %u", &limit); + if (numscan == 1) { + print_monitoring(limit); + } + } +} + +static void print_monitoring(int limit) { + for (int i=0;iInstance->NDTR; + // Re-run state-machine forever + for (;;) { + //Inialize recieve state machine + bool reset_read_state = false; + bool read_active = false; + uint32_t parse_buffer_idx = 0; + //Run state machine until reset + do { + // Fetch the circular buffer "write pointer", where it would write next + uint32_t rcv_idx = UART_BUFFER_SIZE - huart4.hdmarx->Instance->NDTR; + // During sleeping, we may have fallen several characters behind, so we keep + // going until we are caught up, before we sleep again + while (rcv_idx != last_rcv_idx) { + // Fetch the next char, rotate read ptr + uint8_t c = dma_circ_buffer[last_rcv_idx]; + if (++last_rcv_idx == UART_BUFFER_SIZE) + last_rcv_idx = 0; + // Look for start character + if (c == '$') { + read_active = true; + continue; // do not record start char + } + // Record into parse buffer when actively reading + if (read_active) { + parse_buffer[parse_buffer_idx++] = c; + if (c == '\r' || c == '\n' || c == '!') { + // End of command string: exchange end char with terminating null + parse_buffer[parse_buffer_idx-1] = '\0'; + motor_parse_cmd(parse_buffer, parse_buffer_idx); + // Reset receieve state machine + reset_read_state = true; + break; + } else if (parse_buffer_idx == UART_BUFFER_SIZE - 1) { + // We are not at end of command, and receiving another character after this + // would go into the last slot, which is reserved for terminating null. + // We have effectively overflowed parse buffer: abort. + reset_read_state = true; + break; + } + } + } + // When we reach here, we are out of immediate characters to fetch out of buffer + // So we sleep for a bit. + osDelay(1); + } while (!reset_read_state); + } + + for (;;) { + // Wait for signalling from USB interrupt (OTG_FS_IRQHandler) + osSemaphoreWait(sem_usb_irq, osWaitForever); + // Irq processing loop + //while(HAL_NVIC_GetActive(OTG_FS_IRQn)) { + HAL_PCD_IRQHandler(&hpcd_USB_OTG_FS); + //} + // Let the irq (OTG_FS_IRQHandler) fire again. + HAL_NVIC_EnableIRQ(OTG_FS_IRQn); + } + + // If we get here, then this task is done + vTaskDelete(osThreadGetId()); +} \ No newline at end of file diff --git a/MotorControl/commands.h b/MotorControl/commands.h new file mode 100644 index 00000000..ec5e101a --- /dev/null +++ b/MotorControl/commands.h @@ -0,0 +1,10 @@ +#ifndef COMMANDS_H +#define COMMANDS_H + +#include + +/* Exported functions --------------------------------------------------------*/ +void cmd_parse_thread(void const * argument); +void motor_parse_cmd(uint8_t* buffer, int len); + +#endif /* COMMANDS_H */ diff --git a/MotorControl/low_level.c b/MotorControl/low_level.c index a7cf7fa2..5a219052 100755 --- a/MotorControl/low_level.c +++ b/MotorControl/low_level.c @@ -34,6 +34,11 @@ // Arbitrary non-zero inital value to avoid division by zero if ADC reading is late float vbus_voltage = 12.0f; +// For now, this automatically updates to the interface that most +// recently recieved a command. In the future we may want to separate +// debug printf and the main serial comms. +SerialPrintf_t serial_printf_select = SERIAL_PRINTF_IS_NONE; + // TODO stick parameter into struct #define ENCODER_CPR (600*4) #define POLE_PAIRS 7 @@ -221,107 +226,9 @@ static const int current_meas_hz = CURRENT_MEAS_HZ; /* Private variables ---------------------------------------------------------*/ static float brake_resistance = 0.47f; // [ohm] -/* Monitoring */ -monitoring_slot monitoring_slots[20] = {0}; - -/* variables exposed to usb interface via set/get/monitor - * If you change something here, don't forget to regenerate the python interface with generate_api.py - * ro/rw : read only/read write -> ro prevents the code generator from generating setter - * */ - -float* exposed_floats[] = { - &vbus_voltage, // ro - &elec_rad_per_enc, // ro - &motors[0].pos_setpoint, // rw - &motors[0].pos_gain, // rw - &motors[0].vel_setpoint, // rw - &motors[0].vel_gain, // rw - &motors[0].vel_integrator_gain, // rw - &motors[0].vel_integrator_current, // rw - &motors[0].vel_limit, // rw - &motors[0].current_setpoint, // rw - &motors[0].calibration_current, // rw - &motors[0].phase_inductance, // ro - &motors[0].phase_resistance, // ro - &motors[0].current_meas.phB, // ro - &motors[0].current_meas.phC, // ro - &motors[0].DC_calib.phB, // rw - &motors[0].DC_calib.phC, // rw - &motors[0].shunt_conductance, // rw - &motors[0].phase_current_rev_gain, // rw - &motors[0].current_control.current_lim, // rw - &motors[0].current_control.p_gain, // rw - &motors[0].current_control.i_gain, // rw - &motors[0].current_control.v_current_control_integral_d, // rw - &motors[0].current_control.v_current_control_integral_q, // rw - &motors[0].current_control.Ibus, // ro - &motors[0].encoder.phase, // ro - &motors[0].encoder.pll_pos, // rw - &motors[0].encoder.pll_vel, // rw - &motors[0].encoder.pll_kp, // rw - &motors[0].encoder.pll_ki, // rw - &motors[1].pos_setpoint, // rw - &motors[1].pos_gain, // rw - &motors[1].vel_setpoint, // rw - &motors[1].vel_gain, // rw - &motors[1].vel_integrator_gain, // rw - &motors[1].vel_integrator_current, // rw - &motors[1].vel_limit, // rw - &motors[1].current_setpoint, // rw - &motors[1].calibration_current, // rw - &motors[1].phase_inductance, // ro - &motors[1].phase_resistance, // ro - &motors[1].current_meas.phB, // ro - &motors[1].current_meas.phC, // ro - &motors[1].DC_calib.phB, // rw - &motors[1].DC_calib.phC, // rw - &motors[1].shunt_conductance, // rw - &motors[1].phase_current_rev_gain, // rw - &motors[1].current_control.current_lim, // rw - &motors[1].current_control.p_gain, // rw - &motors[1].current_control.i_gain, // rw - &motors[1].current_control.v_current_control_integral_d, // rw - &motors[1].current_control.v_current_control_integral_q, // rw - &motors[1].current_control.Ibus, // ro - &motors[1].encoder.phase, // ro - &motors[1].encoder.pll_pos, // rw - &motors[1].encoder.pll_vel, // rw - &motors[1].encoder.pll_kp, // rw - &motors[1].encoder.pll_ki, // rw -}; - -int* exposed_ints[] = { - (int*)&motors[0].control_mode, // rw - &motors[0].encoder.encoder_offset, // rw - &motors[0].encoder.encoder_state, // ro - &motors[0].error, // rw - (int*)&motors[1].control_mode, // rw - &motors[1].encoder.encoder_offset, // rw - &motors[1].encoder.encoder_state, // ro - &motors[1].error, // rw -}; - -bool* exposed_bools[] = { - &motors[0].thread_ready, // ro - &motors[0].enable_control, // rw - &motors[0].do_calibration, // rw - &motors[0].calibration_ok, // ro - &motors[1].thread_ready, // ro - &motors[1].enable_control, // rw - &motors[1].do_calibration, // rw - &motors[1].calibration_ok, // ro -}; - -uint16_t* exposed_uint16[] = { - &motors[0].control_deadline, // rw - &motors[0].last_cpu_time, // ro - &motors[1].control_deadline, // rw - &motors[1].last_cpu_time, // ro -}; - /* Private function prototypes -----------------------------------------------*/ // Command Handling -static void print_monitoring(int limit); + // Utility static uint16_t check_timing(Motor_t* motor); static void global_fault(int error); @@ -361,27 +268,7 @@ static void control_motor_loop(Motor_t* motor); // TODO move to different file //-------------------------------- -static void print_monitoring(int limit) { - for (int i=0;ipos_setpoint = pos_setpoint; @@ -410,109 +297,6 @@ void set_current_setpoint(Motor_t* motor, float current_setpoint) { #endif } -void motor_parse_cmd(uint8_t* buffer, int len) { - - // TODO very hacky way of terminating sscanf at end of buffer: - // We should do some proper struct packing instead of using sscanf altogether - buffer[len] = 0; - - // check incoming packet type - if (buffer[0] == 'p') { - // position control - unsigned motor_number; - float pos_setpoint, vel_feed_forward, current_feed_forward; - int numscan = sscanf((const char*)buffer, "p %u %f %f %f", &motor_number, &pos_setpoint, &vel_feed_forward, ¤t_feed_forward); - if (numscan == 4 && motor_number < num_motors) { - set_pos_setpoint(&motors[motor_number], pos_setpoint, vel_feed_forward, current_feed_forward); - } - } else if (buffer[0] == 'v') { - // velocity control - unsigned motor_number; - float vel_feed_forward, current_feed_forward; - int numscan = sscanf((const char*)buffer, "v %u %f %f", &motor_number, &vel_feed_forward, ¤t_feed_forward); - if (numscan == 3 && motor_number < num_motors) { - set_vel_setpoint(&motors[motor_number], vel_feed_forward, current_feed_forward); - } - } else if (buffer[0] == 'c') { - // current control - unsigned motor_number; - float current_feed_forward; - int numscan = sscanf((const char*)buffer, "c %u %f", &motor_number, ¤t_feed_forward); - if (numscan == 2 && motor_number < num_motors) { - set_current_setpoint(&motors[motor_number], current_feed_forward); - } - } else if (buffer[0] == 'g') { // GET - // g <0:float,1:int,2:bool,3:uint16> index - int type = 0; - int index = 0; - int numscan = sscanf((const char*)buffer, "g %u %u", &type, &index); - if (numscan == 2) { - switch(type){ - case 0: { - printf("%f\n",*exposed_floats[index]); - break; - }; - case 1: { - printf("%d\n",*exposed_ints[index]); - break; - }; - case 2: { - printf("%d\n",*exposed_bools[index]); - break; - }; - case 3: { - printf("%hu\n",*exposed_uint16[index]); - break; - }; - } - } - } else if (buffer[0] == 's') { // SET - // s <0:float,1:int,2:bool,3:uint16> index value - int type = 0; - int index = 0; - int numscan = sscanf((const char*)buffer, "s %u %u", &type, &index); - if (numscan == 2) { - switch(type) { - case 0: { - sscanf((const char*)buffer, "s %u %u %f", &type, &index, exposed_floats[index]); - break; - }; - case 1: { - sscanf((const char*)buffer, "s %u %u %d", &type, &index, exposed_ints[index]); - break; - }; - case 2: { - int btmp = 0; - sscanf((const char*)buffer, "s %u %u %d", &type, &index, &btmp); - *exposed_bools[index] = btmp ? true : false; - break; - }; - case 3: { - sscanf((const char*)buffer, "s %u %u %hu", &type, &index, exposed_uint16[index]); - break; - }; - } - } - } else if (buffer[0] == 'm') { // Setup Monitor - // m <0:float,1:int,2:bool,3:uint16> index monitoring_slot - int type = 0; - int index = 0; - int slot = 0; - int numscan = sscanf((const char*)buffer, "m %u %u %u", &type, &index, &slot); - if (numscan == 3) { - monitoring_slots[slot].type = type; - monitoring_slots[slot].index = index; - } - } else if (buffer[0] == 'o') { // Output Monitor - int limit = 0; - int numscan = sscanf((const char*)buffer, "o %u", &limit); - if (numscan == 1) { - print_monitoring(limit); - } - } -} - - //-------------------------------- // Utility //-------------------------------- @@ -1050,6 +834,7 @@ static bool motor_calibration(Motor_t* motor){ // Test functions //-------------------------------- +__attribute__((unused)) static void scan_motor_loop(Motor_t* motor, float omega, float voltage_magnitude) { for (;;) { for (float ph = 0.0f; ph < 2.0f * M_PI; ph += omega * current_meas_period) { @@ -1069,6 +854,7 @@ static void scan_motor_loop(Motor_t* motor, float omega, float voltage_magnitude } //TODO integrate as mode in main control loop +__attribute__((unused)) static void FOC_voltage_loop(Motor_t* motor, float v_d, float v_q) { for (;;) { osSignalWait(M_SIGNAL_PH_CURRENT_MEAS, osWaitForever); diff --git a/MotorControl/low_level.h b/MotorControl/low_level.h index 5f0f7f80..5df86f39 100644 --- a/MotorControl/low_level.h +++ b/MotorControl/low_level.h @@ -142,10 +142,17 @@ typedef struct{ int index; } monitoring_slot; +typedef enum { + SERIAL_PRINTF_IS_NONE, + SERIAL_PRINTF_IS_USB, + SERIAL_PRINTF_IS_UART, +} SerialPrintf_t; + /* Exported constants --------------------------------------------------------*/ extern float vbus_voltage; extern Motor_t motors[]; extern const int num_motors; +extern SerialPrintf_t serial_printf_select; /* Exported variables --------------------------------------------------------*/ /* Exported macro ------------------------------------------------------------*/ @@ -165,7 +172,4 @@ void vbus_sense_adc_cb(ADC_HandleTypeDef* hadc, bool injected); //@TODO move motor thread to high level file void motor_thread(void const * argument); -//@TODO move cmd parsing to high level file -void motor_parse_cmd(uint8_t* buffer, int len); - #endif //__LOW_LEVEL_H diff --git a/Src/freertos.c b/Src/freertos.c index a61e7ee9..b8cee15a 100644 --- a/Src/freertos.c +++ b/Src/freertos.c @@ -54,15 +54,14 @@ /* USER CODE BEGIN Includes */ #include "freertos_vars.h" #include "low_level.h" -#include "usart.h" -#include "version.h" +#include "commands.h" /* USER CODE END Includes */ /* Variables -----------------------------------------------------------------*/ osThreadId defaultTaskHandle; /* USER CODE BEGIN Variables */ -extern PCD_HandleTypeDef hpcd_USB_OTG_FS; + /* USER CODE END Variables */ /* Function prototypes -------------------------------------------------------*/ @@ -143,89 +142,6 @@ void StartDefaultTask(void const * argument) /* USER CODE BEGIN Application */ -//TODO move this to a different file -// Thread to handle deffered processing of USB interrupt -void usb_cmd_thread(void const * argument) { - - //DMA open loop continous circular buffer - //1ms delay periodic, chase DMA ptr around, on new data: - // Check for start char - // copy into parse-buffer - // check for end-char - // checksum, etc. - - #define UART_BUFFER_SIZE 64 - static uint8_t dma_circ_buffer[UART_BUFFER_SIZE]; - static uint8_t parse_buffer[UART_BUFFER_SIZE]; - - // DMA is set up to recieve in a circular buffer forever. - // We dont use interrupts to fetch the data, instead we periodically read - // data out of the circular buffer into a parse buffer, controlled by a state machine - HAL_UART_Receive_DMA(&huart4, dma_circ_buffer, sizeof(dma_circ_buffer)); - - uint32_t last_rcv_idx = UART_BUFFER_SIZE - huart4.hdmarx->Instance->NDTR; - // Re-run state-machine forever - for (;;) { - //Inialize recieve state machine - bool reset_read_state = false; - bool read_active = false; - uint32_t parse_buffer_idx = 0; - //Run state machine until reset - do { - // Fetch the circular buffer "write pointer", where it would write next - uint32_t rcv_idx = UART_BUFFER_SIZE - huart4.hdmarx->Instance->NDTR; - // During sleeping, we may have fallen several characters behind, so we keep - // going until we are caught up, before we sleep again - while (rcv_idx != last_rcv_idx) { - // Fetch the next char, rotate read ptr - uint8_t c = dma_circ_buffer[last_rcv_idx]; - if (++last_rcv_idx == UART_BUFFER_SIZE) - last_rcv_idx = 0; - // Look for start character - if (c == '$') { - read_active = true; - continue; // do not record start char - } - // Record into parse buffer when actively reading - if (read_active) { - parse_buffer[parse_buffer_idx++] = c; - if (c == '\r' || c == '\n' || c == '!') { - // End of command string: exchange end char with terminating null - parse_buffer[parse_buffer_idx-1] = '\0'; - motor_parse_cmd(parse_buffer, parse_buffer_idx); - // Reset receieve state machine - reset_read_state = true; - break; - } else if (parse_buffer_idx == UART_BUFFER_SIZE - 1) { - // We are not at end of command, and receiving another character after this - // would go into the last slot, which is reserved for terminating null. - // We have effectively overflowed parse buffer: abort. - reset_read_state = true; - break; - } - } - } - // When we reach here, we are out of immediate characters to fetch out of buffer - // So we sleep for a bit. - osDelay(1); - } while (!reset_read_state); - } - - for (;;) { - // Wait for signalling from USB interrupt (OTG_FS_IRQHandler) - osSemaphoreWait(sem_usb_irq, osWaitForever); - // Irq processing loop - //while(HAL_NVIC_GetActive(OTG_FS_IRQn)) { - HAL_PCD_IRQHandler(&hpcd_USB_OTG_FS); - //} - // Let the irq (OTG_FS_IRQHandler) fire again. - HAL_NVIC_EnableIRQ(OTG_FS_IRQn); - } - - // If we get here, then this task is done - vTaskDelete(osThreadGetId()); -} - /* USER CODE END Application */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/Src/syscalls.c b/Src/syscalls.c index 7a2e590a..d8fd9283 100644 --- a/Src/syscalls.c +++ b/Src/syscalls.c @@ -7,6 +7,7 @@ #include #include "usbd_cdc_if.h" +#include //int _read(int file, char *data, int len) {} //int _close(int file) {} diff --git a/Src/usbd_cdc_if.c b/Src/usbd_cdc_if.c index 862cd359..a9d9d29c 100644 --- a/Src/usbd_cdc_if.c +++ b/Src/usbd_cdc_if.c @@ -50,7 +50,7 @@ #include "usbd_cdc_if.h" /* USER CODE BEGIN INCLUDE */ #include "utils.h" -#include "low_level.h" +#include "commands.h" /* USER CODE END INCLUDE */ /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY From a4af9f1b98d23576e7af2178ccfef0da55a1e6a9 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Tue, 10 Oct 2017 21:42:21 -0700 Subject: [PATCH 25/35] USB and UART arbitration WIP --- MotorControl/commands.c | 15 ++++++++++++--- MotorControl/commands.h | 15 ++++++++++++++- MotorControl/low_level.c | 5 ----- MotorControl/low_level.h | 12 ++---------- Odrive.ioc | 10 ++++++---- Src/syscalls.c | 23 +++++++++++++++++++---- Src/usbd_cdc_if.c | 15 +++++++++------ 7 files changed, 62 insertions(+), 33 deletions(-) diff --git a/MotorControl/commands.c b/MotorControl/commands.c index 8674a256..83b0f3ee 100644 --- a/MotorControl/commands.c +++ b/MotorControl/commands.c @@ -3,11 +3,17 @@ #include #include +extern PCD_HandleTypeDef hpcd_USB_OTG_FS; + /* Private macros ------------------------------------------------------------*/ /* Private typedef -----------------------------------------------------------*/ /* Global constant data ------------------------------------------------------*/ /* Global variables ----------------------------------------------------------*/ -extern PCD_HandleTypeDef hpcd_USB_OTG_FS; +// For now, this automatically updates to the interface that most +// recently recieved a command. In the future we may want to separate +// debug printf and the main serial comms. +SerialPrintf_t serial_printf_select = SERIAL_PRINTF_IS_NONE; + /* Private constant data -----------------------------------------------------*/ // variables exposed to usb/serial interface via set/get/monitor // Note: this will be depricated soon @@ -107,7 +113,10 @@ monitoring_slot monitoring_slots[20] = {0}; static void print_monitoring(int limit); /* Function implementations --------------------------------------------------*/ -void motor_parse_cmd(uint8_t* buffer, int len) { +void motor_parse_cmd(uint8_t* buffer, int len, SerialPrintf_t response_interface) { + // Set response interface + serial_printf_select = response_interface; + // TODO very hacky way of terminating sscanf at end of buffer: // We should do some proper struct packing instead of using sscanf altogether buffer[len] = 0; @@ -279,7 +288,7 @@ void usb_cmd_thread(void const * argument) { if (c == '\r' || c == '\n' || c == '!') { // End of command string: exchange end char with terminating null parse_buffer[parse_buffer_idx-1] = '\0'; - motor_parse_cmd(parse_buffer, parse_buffer_idx); + motor_parse_cmd(parse_buffer, parse_buffer_idx, SERIAL_PRINTF_IS_UART); // Reset receieve state machine reset_read_state = true; break; diff --git a/MotorControl/commands.h b/MotorControl/commands.h index ec5e101a..a23756b8 100644 --- a/MotorControl/commands.h +++ b/MotorControl/commands.h @@ -1,10 +1,23 @@ #ifndef COMMANDS_H #define COMMANDS_H +/* Includes ------------------------------------------------------------------*/ #include +/* Exported types ------------------------------------------------------------*/ +typedef enum { + SERIAL_PRINTF_IS_NONE, + SERIAL_PRINTF_IS_USB, + SERIAL_PRINTF_IS_UART, +} SerialPrintf_t; + +/* Exported constants --------------------------------------------------------*/ +/* Exported variables --------------------------------------------------------*/ +extern SerialPrintf_t serial_printf_select; +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions --------------------------------------------------------*/ /* Exported functions --------------------------------------------------------*/ void cmd_parse_thread(void const * argument); -void motor_parse_cmd(uint8_t* buffer, int len); +void motor_parse_cmd(uint8_t* buffer, int len, SerialPrintf_t response_interface); #endif /* COMMANDS_H */ diff --git a/MotorControl/low_level.c b/MotorControl/low_level.c index 5a219052..6f799f4c 100755 --- a/MotorControl/low_level.c +++ b/MotorControl/low_level.c @@ -34,11 +34,6 @@ // Arbitrary non-zero inital value to avoid division by zero if ADC reading is late float vbus_voltage = 12.0f; -// For now, this automatically updates to the interface that most -// recently recieved a command. In the future we may want to separate -// debug printf and the main serial comms. -SerialPrintf_t serial_printf_select = SERIAL_PRINTF_IS_NONE; - // TODO stick parameter into struct #define ENCODER_CPR (600*4) #define POLE_PAIRS 7 diff --git a/MotorControl/low_level.h b/MotorControl/low_level.h index 5df86f39..49012092 100644 --- a/MotorControl/low_level.h +++ b/MotorControl/low_level.h @@ -142,19 +142,11 @@ typedef struct{ int index; } monitoring_slot; -typedef enum { - SERIAL_PRINTF_IS_NONE, - SERIAL_PRINTF_IS_USB, - SERIAL_PRINTF_IS_UART, -} SerialPrintf_t; - /* Exported constants --------------------------------------------------------*/ +extern const int num_motors; +/* Exported variables --------------------------------------------------------*/ extern float vbus_voltage; extern Motor_t motors[]; -extern const int num_motors; -extern SerialPrintf_t serial_printf_select; - -/* Exported variables --------------------------------------------------------*/ /* Exported macro ------------------------------------------------------------*/ /* Exported functions --------------------------------------------------------*/ diff --git a/Odrive.ioc b/Odrive.ioc index 1c222c69..86cc79fd 100755 --- a/Odrive.ioc +++ b/Odrive.ioc @@ -592,11 +592,13 @@ TIM8.Period=TIM_1_8_PERIOD_CLOCKS TIM8.TIM_MasterOutputTrigger=TIM_TRGO_UPDATE UART4.IPParameters=VirtualMode UART4.VirtualMode=Asynchronous +USB_DEVICE.APP_RX_DATA_SIZE-CDC_FS=64 +USB_DEVICE.APP_TX_DATA_SIZE-CDC_FS=64 USB_DEVICE.CLASS_NAME_FS=CDC -USB_DEVICE.IPParameters=VirtualMode-CDC_FS,VirtualModeFS,CLASS_NAME_FS,MANUFACTURER_STRING-CDC_FS,PRODUCT_STRING_CDC_FS,VID-CDC_FS,PID_CDC_FS,SERIALNUMBER_STRING_CDC_FS -USB_DEVICE.MANUFACTURER_STRING-CDC_FS=ODrive -USB_DEVICE.PID_CDC_FS=0x0D31 -USB_DEVICE.PRODUCT_STRING_CDC_FS=ODrive rev 3.1 +USB_DEVICE.IPParameters=VirtualMode-CDC_FS,VirtualModeFS,CLASS_NAME_FS,MANUFACTURER_STRING-CDC_FS,PRODUCT_STRING_CDC_FS,VID-CDC_FS,PID_CDC_FS,SERIALNUMBER_STRING_CDC_FS,APP_RX_DATA_SIZE-CDC_FS,APP_TX_DATA_SIZE-CDC_FS +USB_DEVICE.MANUFACTURER_STRING-CDC_FS=ODrive Robotics +USB_DEVICE.PID_CDC_FS=0x0D33 +USB_DEVICE.PRODUCT_STRING_CDC_FS=ODrive rev 3.3 USB_DEVICE.SERIALNUMBER_STRING_CDC_FS=000000000001 USB_DEVICE.VID-CDC_FS=0x1209 USB_DEVICE.VirtualMode-CDC_FS=Cdc diff --git a/Src/syscalls.c b/Src/syscalls.c index d8fd9283..cce3b77e 100644 --- a/Src/syscalls.c +++ b/Src/syscalls.c @@ -15,11 +15,26 @@ //int _fstat(int file, struct stat *st) {} //int _isatty(int file) {} +//static char uart_tx_buf + int _write(int file, char *data, int len) { - // transmit over CDC - uint8_t status = CDC_Transmit_FS((uint8_t*)data, len); + //number of bytes written + int written = 0; - // return number of bytes written - return (status == USBD_OK ? len : 0); + switch (serial_printf_select) { + case SERIAL_PRINTF_IS_USB: { + // transmit over CDC + uint8_t status = CDC_Transmit_FS((uint8_t*)data, len); + written = (status == USBD_OK) ? len : 0; + } break; + case SERIAL_PRINTF_IS_UART: { + + } break; + default: { + written = 0; + } break; + } + + return written; } diff --git a/Src/usbd_cdc_if.c b/Src/usbd_cdc_if.c index a9d9d29c..50696d9b 100644 --- a/Src/usbd_cdc_if.c +++ b/Src/usbd_cdc_if.c @@ -275,7 +275,7 @@ static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len) int null_idx = MACRO_MIN(*Len, APP_RX_DATA_SIZE-1); Buf[null_idx] = 0; - motor_parse_cmd(Buf, *Len); + motor_parse_cmd(Buf, *Len, SERIAL_PRINTF_IS_USB); return (USBD_OK); /* USER CODE END 6 */ @@ -296,11 +296,14 @@ uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) { uint8_t result = USBD_OK; /* USER CODE BEGIN 7 */ - USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData; - if (hcdc->TxState != 0){ - return USBD_BUSY; - } - USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len); + + //Check Len + if (Len > APP_TX_DATA_SIZE) + return USBD_FAIL; + // memcpy Buf into UserTxBufferFS + memcpy(UserTxBufferFS, Buf, Len); + // Update Len + USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, Len); result = USBD_CDC_TransmitPacket(&hUsbDeviceFS); /* USER CODE END 7 */ return result; From 23d7bbdeaa2fb5973fb9897c1ce2d8a354b67f7b Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Tue, 10 Oct 2017 22:37:23 -0700 Subject: [PATCH 26/35] working bidirectional arbitrated UART and USB comms --- Inc/freertos_vars.h | 2 +- MotorControl/commands.c | 43 ++++++++++++++++++++--------------------- Src/freertos.c | 5 ++--- Src/syscalls.c | 23 +++++++++++++++++----- Src/usbd_cdc_if.c | 2 +- Src/usbd_desc.c | 2 +- 6 files changed, 44 insertions(+), 33 deletions(-) diff --git a/Inc/freertos_vars.h b/Inc/freertos_vars.h index a0bc6d2b..fd0bf85d 100644 --- a/Inc/freertos_vars.h +++ b/Inc/freertos_vars.h @@ -8,6 +8,6 @@ osSemaphoreId sem_usb_irq; // List of threads osThreadId thread_motor_0; osThreadId thread_motor_1; -osThreadId thread_usb_cmd; +osThreadId thread_cmd_parse; #endif /* __FREERTOS_H */ \ No newline at end of file diff --git a/MotorControl/commands.c b/MotorControl/commands.c index 83b0f3ee..1eeef4ac 100644 --- a/MotorControl/commands.c +++ b/MotorControl/commands.c @@ -1,4 +1,5 @@ /* Includes ------------------------------------------------------------------*/ +#include #include #include #include @@ -241,7 +242,7 @@ static void print_monitoring(int limit) { // Thread to handle deffered processing of USB interrupt, and // read commands out of the UART DMA circular buffer -void usb_cmd_thread(void const * argument) { +void cmd_parse_thread(void const * argument) { //DMA open loop continous circular buffer //1ms delay periodic, chase DMA ptr around, on new data: @@ -250,16 +251,16 @@ void usb_cmd_thread(void const * argument) { // check for end-char // checksum, etc. - #define UART_BUFFER_SIZE 64 - static uint8_t dma_circ_buffer[UART_BUFFER_SIZE]; - static uint8_t parse_buffer[UART_BUFFER_SIZE]; + #define UART_RX_BUFFER_SIZE 64 + static uint8_t dma_circ_buffer[UART_RX_BUFFER_SIZE]; + static uint8_t parse_buffer[UART_RX_BUFFER_SIZE]; // DMA is set up to recieve in a circular buffer forever. // We dont use interrupts to fetch the data, instead we periodically read // data out of the circular buffer into a parse buffer, controlled by a state machine HAL_UART_Receive_DMA(&huart4, dma_circ_buffer, sizeof(dma_circ_buffer)); - uint32_t last_rcv_idx = UART_BUFFER_SIZE - huart4.hdmarx->Instance->NDTR; + uint32_t last_rcv_idx = UART_RX_BUFFER_SIZE - huart4.hdmarx->Instance->NDTR; // Re-run state-machine forever for (;;) { //Inialize recieve state machine @@ -269,13 +270,13 @@ void usb_cmd_thread(void const * argument) { //Run state machine until reset do { // Fetch the circular buffer "write pointer", where it would write next - uint32_t rcv_idx = UART_BUFFER_SIZE - huart4.hdmarx->Instance->NDTR; + uint32_t rcv_idx = UART_RX_BUFFER_SIZE - huart4.hdmarx->Instance->NDTR; // During sleeping, we may have fallen several characters behind, so we keep // going until we are caught up, before we sleep again while (rcv_idx != last_rcv_idx) { // Fetch the next char, rotate read ptr uint8_t c = dma_circ_buffer[last_rcv_idx]; - if (++last_rcv_idx == UART_BUFFER_SIZE) + if (++last_rcv_idx == UART_RX_BUFFER_SIZE) last_rcv_idx = 0; // Look for start character if (c == '$') { @@ -292,7 +293,7 @@ void usb_cmd_thread(void const * argument) { // Reset receieve state machine reset_read_state = true; break; - } else if (parse_buffer_idx == UART_BUFFER_SIZE - 1) { + } else if (parse_buffer_idx == UART_RX_BUFFER_SIZE - 1) { // We are not at end of command, and receiving another character after this // would go into the last slot, which is reserved for terminating null. // We have effectively overflowed parse buffer: abort. @@ -301,23 +302,21 @@ void usb_cmd_thread(void const * argument) { } } } - // When we reach here, we are out of immediate characters to fetch out of buffer - // So we sleep for a bit. - osDelay(1); + // When we reach here, we are out of immediate characters to fetch out of UART buffer + // Now we check if there is any USB processing to do: we wait for up to 1 ms, + // before going back to checking UART again. + int USB_check_timeout = 1; + // Wait for signalling from USB interrupt (OTG_FS_IRQHandler) + osStatus semaphore_status = osSemaphoreWait(sem_usb_irq, USB_check_timeout); + if (semaphore_status == osOK) { + // We have a new incoming USB transmission: handle it + HAL_PCD_IRQHandler(&hpcd_USB_OTG_FS); + // Let the irq (OTG_FS_IRQHandler) fire again. + HAL_NVIC_EnableIRQ(OTG_FS_IRQn); + } } while (!reset_read_state); } - for (;;) { - // Wait for signalling from USB interrupt (OTG_FS_IRQHandler) - osSemaphoreWait(sem_usb_irq, osWaitForever); - // Irq processing loop - //while(HAL_NVIC_GetActive(OTG_FS_IRQn)) { - HAL_PCD_IRQHandler(&hpcd_USB_OTG_FS); - //} - // Let the irq (OTG_FS_IRQHandler) fire again. - HAL_NVIC_EnableIRQ(OTG_FS_IRQn); - } - // If we get here, then this task is done vTaskDelete(osThreadGetId()); } \ No newline at end of file diff --git a/Src/freertos.c b/Src/freertos.c index b8cee15a..62d3a451 100644 --- a/Src/freertos.c +++ b/Src/freertos.c @@ -71,7 +71,6 @@ extern void MX_USB_DEVICE_Init(void); void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */ /* USER CODE BEGIN FunctionPrototypes */ -void usb_cmd_thread(void const * argument); /* USER CODE END FunctionPrototypes */ @@ -131,8 +130,8 @@ void StartDefaultTask(void const * argument) thread_motor_1 = osThreadCreate(osThread(task_motor_1), &motors[1]); // Start USB command handling thread - osThreadDef(task_usb_cmd, usb_cmd_thread, osPriorityNormal, 0, 512); - thread_usb_cmd = osThreadCreate(osThread(task_usb_cmd), NULL); + osThreadDef(task_cmd_parse, cmd_parse_thread, osPriorityNormal, 0, 512); + thread_cmd_parse = osThreadCreate(osThread(task_cmd_parse), NULL); //If we get to here, then the default task is done. vTaskDelete(defaultTaskHandle); diff --git a/Src/syscalls.c b/Src/syscalls.c index cce3b77e..3cd2a073 100644 --- a/Src/syscalls.c +++ b/Src/syscalls.c @@ -6,31 +6,44 @@ */ #include -#include "usbd_cdc_if.h" +#include +#include #include + //int _read(int file, char *data, int len) {} //int _close(int file) {} //int _lseek(int file, int ptr, int dir) {} //int _fstat(int file, struct stat *st) {} //int _isatty(int file) {} -//static char uart_tx_buf +#define UART_TX_BUFFER_SIZE 64 +static uint8_t uart_tx_buf[UART_TX_BUFFER_SIZE]; int _write(int file, char *data, int len) { - //number of bytes written int written = 0; - switch (serial_printf_select) { + case SERIAL_PRINTF_IS_USB: { // transmit over CDC uint8_t status = CDC_Transmit_FS((uint8_t*)data, len); written = (status == USBD_OK) ? len : 0; } break; - case SERIAL_PRINTF_IS_UART: { + case SERIAL_PRINTF_IS_UART: { + //Check length + if (len > UART_TX_BUFFER_SIZE) + return 0; + // Check if transfer is already ongoing + if(huart4.gState != HAL_UART_STATE_READY) + return 0; + // memcpy data into uart_tx_buf + memcpy(uart_tx_buf, data, len); + // Start DMA background trasnfer + HAL_UART_Transmit_DMA(&huart4, uart_tx_buf, len); } break; + default: { written = 0; } break; diff --git a/Src/usbd_cdc_if.c b/Src/usbd_cdc_if.c index 50696d9b..632c5f41 100644 --- a/Src/usbd_cdc_if.c +++ b/Src/usbd_cdc_if.c @@ -297,7 +297,7 @@ uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) uint8_t result = USBD_OK; /* USER CODE BEGIN 7 */ - //Check Len + //Check length if (Len > APP_TX_DATA_SIZE) return USBD_FAIL; // memcpy Buf into UserTxBufferFS diff --git a/Src/usbd_desc.c b/Src/usbd_desc.c index 1e8f425f..54a656ac 100644 --- a/Src/usbd_desc.c +++ b/Src/usbd_desc.c @@ -75,7 +75,7 @@ #define USBD_LANGID_STRING 1033 #define USBD_MANUFACTURER_STRING "ODrive" #define USBD_PID_FS 0x0D31 -#define USBD_PRODUCT_STRING_FS "ODrive rev 3.1" +#define USBD_PRODUCT_STRING_FS "ODrive v3.1" #define USBD_SERIALNUMBER_STRING_FS "000000000001" #define USBD_CONFIGURATION_STRING_FS "CDC Config" #define USBD_INTERFACE_STRING_FS "CDC Interface" From 5c22ef1973d0cc0d5b8e4a6e3d1cdf8ca5291a3d Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Tue, 10 Oct 2017 22:48:16 -0700 Subject: [PATCH 27/35] update USBstr in cube --- Odrive.ioc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Odrive.ioc b/Odrive.ioc index 86cc79fd..21fd7b97 100755 --- a/Odrive.ioc +++ b/Odrive.ioc @@ -598,7 +598,7 @@ USB_DEVICE.CLASS_NAME_FS=CDC USB_DEVICE.IPParameters=VirtualMode-CDC_FS,VirtualModeFS,CLASS_NAME_FS,MANUFACTURER_STRING-CDC_FS,PRODUCT_STRING_CDC_FS,VID-CDC_FS,PID_CDC_FS,SERIALNUMBER_STRING_CDC_FS,APP_RX_DATA_SIZE-CDC_FS,APP_TX_DATA_SIZE-CDC_FS USB_DEVICE.MANUFACTURER_STRING-CDC_FS=ODrive Robotics USB_DEVICE.PID_CDC_FS=0x0D33 -USB_DEVICE.PRODUCT_STRING_CDC_FS=ODrive rev 3.3 +USB_DEVICE.PRODUCT_STRING_CDC_FS=ODrive v3.3 USB_DEVICE.SERIALNUMBER_STRING_CDC_FS=000000000001 USB_DEVICE.VID-CDC_FS=0x1209 USB_DEVICE.VirtualMode-CDC_FS=Cdc From 8db9d2cc695b37aee3ed157eced3516f5495168c Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Tue, 10 Oct 2017 23:58:02 -0700 Subject: [PATCH 28/35] fix Arduinos being trash --- Inc/stm32f4xx_it.h | 1 + MotorControl/commands.c | 6 ++++++ Odrive.ioc | 1 + Src/stm32f4xx_it.c | 15 +++++++++++++++ Src/syscalls.c | 1 + Src/usart.c | 6 ++++++ Src/usbd_cdc_if.c | 1 + 7 files changed, 31 insertions(+) diff --git a/Inc/stm32f4xx_it.h b/Inc/stm32f4xx_it.h index 8fcd22cf..967b9ca4 100644 --- a/Inc/stm32f4xx_it.h +++ b/Inc/stm32f4xx_it.h @@ -58,6 +58,7 @@ void DMA1_Stream2_IRQHandler(void); void DMA1_Stream4_IRQHandler(void); void ADC_IRQHandler(void); void TIM8_TRG_COM_TIM14_IRQHandler(void); +void UART4_IRQHandler(void); void OTG_FS_IRQHandler(void); #ifdef __cplusplus diff --git a/MotorControl/commands.c b/MotorControl/commands.c index 1eeef4ac..3818cc78 100644 --- a/MotorControl/commands.c +++ b/MotorControl/commands.c @@ -269,6 +269,12 @@ void cmd_parse_thread(void const * argument) { uint32_t parse_buffer_idx = 0; //Run state machine until reset do { + // Check for UART errors and restart recieve DMA transfer if required + if (huart4.ErrorCode != HAL_UART_ERROR_NONE) { + HAL_UART_AbortReceive(&huart4); + HAL_UART_Receive_DMA(&huart4, dma_circ_buffer, sizeof(dma_circ_buffer)); + break; //reset state machine + } // Fetch the circular buffer "write pointer", where it would write next uint32_t rcv_idx = UART_RX_BUFFER_SIZE - huart4.hdmarx->Instance->NDTR; // During sleeping, we may have fallen several characters behind, so we keep diff --git a/Odrive.ioc b/Odrive.ioc index 21fd7b97..b5f504d8 100755 --- a/Odrive.ioc +++ b/Odrive.ioc @@ -208,6 +208,7 @@ NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:true\:true NVIC.TIM8_TRG_COM_TIM14_IRQn=true\:0\:0\:false\:false\:true\:false\:false NVIC.TimeBase=TIM8_TRG_COM_TIM14_IRQn NVIC.TimeBaseIP=TIM14 +NVIC.UART4_IRQn=true\:5\:0\:false\:false\:true\:true\:true NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:true PA0-WKUP.GPIOParameters=GPIO_PuPd,GPIO_Label PA0-WKUP.GPIO_Label=GPIO_1 diff --git a/Src/stm32f4xx_it.c b/Src/stm32f4xx_it.c index 2c3da6a4..18dd5c40 100644 --- a/Src/stm32f4xx_it.c +++ b/Src/stm32f4xx_it.c @@ -57,6 +57,7 @@ extern ADC_HandleTypeDef hadc3; extern TIM_HandleTypeDef htim8; extern DMA_HandleTypeDef hdma_uart4_rx; extern DMA_HandleTypeDef hdma_uart4_tx; +extern UART_HandleTypeDef huart4; extern TIM_HandleTypeDef htim14; @@ -244,6 +245,20 @@ void TIM8_TRG_COM_TIM14_IRQHandler(void) /* USER CODE END TIM8_TRG_COM_TIM14_IRQn 1 */ } +/** +* @brief This function handles UART4 global interrupt. +*/ +void UART4_IRQHandler(void) +{ + /* USER CODE BEGIN UART4_IRQn 0 */ + + /* USER CODE END UART4_IRQn 0 */ + HAL_UART_IRQHandler(&huart4); + /* USER CODE BEGIN UART4_IRQn 1 */ + + /* USER CODE END UART4_IRQn 1 */ +} + /** * @brief This function handles USB On The Go FS global interrupt. */ diff --git a/Src/syscalls.c b/Src/syscalls.c index 3cd2a073..e58a4420 100644 --- a/Src/syscalls.c +++ b/Src/syscalls.c @@ -36,6 +36,7 @@ int _write(int file, char *data, int len) { if (len > UART_TX_BUFFER_SIZE) return 0; // Check if transfer is already ongoing + // TODO: use HAL_UART_GetState if(huart4.gState != HAL_UART_STATE_READY) return 0; // memcpy data into uart_tx_buf diff --git a/Src/usart.c b/Src/usart.c index 58182d39..1704d012 100644 --- a/Src/usart.c +++ b/Src/usart.c @@ -147,6 +147,9 @@ void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) __HAL_LINKDMA(uartHandle,hdmatx,hdma_uart4_tx); + /* UART4 interrupt Init */ + HAL_NVIC_SetPriority(UART4_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(UART4_IRQn); /* USER CODE BEGIN UART4_MspInit 1 */ /* USER CODE END UART4_MspInit 1 */ @@ -173,6 +176,9 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle) /* UART4 DMA DeInit */ HAL_DMA_DeInit(uartHandle->hdmarx); HAL_DMA_DeInit(uartHandle->hdmatx); + + /* UART4 interrupt Deinit */ + HAL_NVIC_DisableIRQ(UART4_IRQn); /* USER CODE BEGIN UART4_MspDeInit 1 */ /* USER CODE END UART4_MspDeInit 1 */ diff --git a/Src/usbd_cdc_if.c b/Src/usbd_cdc_if.c index 632c5f41..57680540 100644 --- a/Src/usbd_cdc_if.c +++ b/Src/usbd_cdc_if.c @@ -300,6 +300,7 @@ uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) //Check length if (Len > APP_TX_DATA_SIZE) return USBD_FAIL; + // TODO: check busy // memcpy Buf into UserTxBufferFS memcpy(UserTxBufferFS, Buf, Len); // Update Len From 0322ef071cfae8dd20058c81359b01924b5e569e Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Wed, 11 Oct 2017 00:13:33 -0700 Subject: [PATCH 29/35] check for usb busy --- Src/syscalls.c | 1 - Src/usbd_cdc_if.c | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Src/syscalls.c b/Src/syscalls.c index e58a4420..3cd2a073 100644 --- a/Src/syscalls.c +++ b/Src/syscalls.c @@ -36,7 +36,6 @@ int _write(int file, char *data, int len) { if (len > UART_TX_BUFFER_SIZE) return 0; // Check if transfer is already ongoing - // TODO: use HAL_UART_GetState if(huart4.gState != HAL_UART_STATE_READY) return 0; // memcpy data into uart_tx_buf diff --git a/Src/usbd_cdc_if.c b/Src/usbd_cdc_if.c index 57680540..e3882cce 100644 --- a/Src/usbd_cdc_if.c +++ b/Src/usbd_cdc_if.c @@ -300,7 +300,10 @@ uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) //Check length if (Len > APP_TX_DATA_SIZE) return USBD_FAIL; - // TODO: check busy + // Check for ongoing transmission + USBD_CDC_HandleTypeDef* hcdc = (USBD_CDC_HandleTypeDef*) hUsbDeviceFS.pClassData; + if (hcdc->TxState != 0) + return USBD_BUSY; // memcpy Buf into UserTxBufferFS memcpy(UserTxBufferFS, Buf, Len); // Update Len From c8ff9e7e6da95b00b15ec091a29dd5ccd4e7c0f1 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Wed, 11 Oct 2017 13:31:15 -0700 Subject: [PATCH 30/35] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1b0c8ec1..11438531 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Like this (click for video): [![Servo motor control demo](https://img.youtube.com/vi/WT4E5nb3KtY/0.jpg)](https://www.youtube.com/watch?v=WT4E5nb3KtY) This repository contains the firmware that runs on the board. The other related repositories are: -* [ODriveHardware](https://github.com/madcowswe/ODriveHardware): Circuit board design. Also, the pinout from the microcontroller to the board is documented [here](https://docs.google.com/spreadsheets/d/1QXDCs1IRtUyG__M_9WruWOheywb-GhOwFtfPcHuN2Fg/edit?usp=sharing). +* [ODriveHardware](https://github.com/madcowswe/ODriveHardware): Circuit board design. Also, the pinout from the microcontroller to the board is documented [here](https://docs.google.com/spreadsheets/d/1QXDCs1IRtUyG__M_9WruWOheywb-GhOwFtfPcHuN2Fg/edit#gid=404444347). * [ODrive](https://github.com/madcowswe/ODrive): Configuration and analysis scripts that runs on a PC. There is also [ODriveFPGA](https://github.com/madcowswe/ODriveFPGA), which contains the FPGA logic and software that runs on the FPGA based ODrive. This is not currently in development, but may be resumed at some later date. @@ -44,7 +44,7 @@ You must set: ### Tuning parameters The most important parameters are the limits: -* The current limit: `.current_lim = 75.0f, //[A] // Note: consistent with 40v/v gain`. The default current limit, for safety reasons, is set to 10A. This is quite weak, and good for making sure the drive is stable. Once you have tuned the drive, you should increase this to 75A to get some performance. Note that above 75A, you must change the current amplifier gains. +* The current limit: `.current_lim = 75.0f, //[A] // Note: consistent with 40v/v gain`. The default current limit, for safety reasons, is set to 10A. This is quite weak, and good for making sure the drive is stable. Once you have tuned the drive, you can increase this to 75A to get some performance. Note that above 75A, you must change the current amplifier gains. * The velocity limit: `.vel_limit = 20000.0f, // [counts/s]`. Does what it says on the tin. The motion control gains are currently manually tuned: From 99b9840455468b8da5bcf84684e669d261d83df7 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Wed, 11 Oct 2017 13:42:59 -0700 Subject: [PATCH 31/35] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62e96abb..1b9b4455 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ -## [0.1] - UNRELEASED +## [0.1.0] - 2017-08-26 ### Added * Step/Dir interface * this Changelog From 8b70924b41643c8a7af4beb21a536b78533ccf53 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sat, 14 Oct 2017 14:45:38 -0700 Subject: [PATCH 32/35] unsafe modification outside buffer fixed --- MotorControl/low_level.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MotorControl/low_level.c b/MotorControl/low_level.c index db44c3b8..d5c18bff 100755 --- a/MotorControl/low_level.c +++ b/MotorControl/low_level.c @@ -414,7 +414,7 @@ void motor_parse_cmd(uint8_t* buffer, int len) { // TODO very hacky way of terminating sscanf at end of buffer: // We should do some proper struct packing instead of using sscanf altogether - buffer[len] = 0; + buffer[len-1] = 0; // check incoming packet type if (buffer[0] == 'p') { From a9a9323ec3526b4e7d41fbaa6ca784714c984a7b Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sat, 14 Oct 2017 17:45:13 -0700 Subject: [PATCH 33/35] fix null writing outside buffer --- MotorControl/commands.c | 2 +- Src/usbd_cdc_if.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/MotorControl/commands.c b/MotorControl/commands.c index 3818cc78..c90579c3 100644 --- a/MotorControl/commands.c +++ b/MotorControl/commands.c @@ -120,7 +120,7 @@ void motor_parse_cmd(uint8_t* buffer, int len, SerialPrintf_t response_interface // TODO very hacky way of terminating sscanf at end of buffer: // We should do some proper struct packing instead of using sscanf altogether - buffer[len] = 0; + buffer[len-1] = 0; // check incoming packet type if (buffer[0] == 'p') { diff --git a/Src/usbd_cdc_if.c b/Src/usbd_cdc_if.c index e3882cce..cca47fc5 100644 --- a/Src/usbd_cdc_if.c +++ b/Src/usbd_cdc_if.c @@ -268,14 +268,14 @@ static int8_t CDC_Control_FS (uint8_t cmd, uint8_t* pbuf, uint16_t length) static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len) { /* USER CODE BEGIN 6 */ - USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]); - USBD_CDC_ReceivePacket(&hUsbDeviceFS); - //Append null termination at end of string - int null_idx = MACRO_MIN(*Len, APP_RX_DATA_SIZE-1); - Buf[null_idx] = 0; + int modified_len = MACRO_MIN(*Len+1, APP_RX_DATA_SIZE); + Buf[modified_len-1] = 0; - motor_parse_cmd(Buf, *Len, SERIAL_PRINTF_IS_USB); + motor_parse_cmd(Buf, modified_len, SERIAL_PRINTF_IS_USB); + + // Allow next packet + USBD_CDC_ReceivePacket(&hUsbDeviceFS); return (USBD_OK); /* USER CODE END 6 */ From fa0547887587cef80306608d191387d8d8e2ecc6 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sat, 14 Oct 2017 18:00:43 -0700 Subject: [PATCH 34/35] implement GPIO 1,2 select --- MotorControl/commands.c | 18 +++++++++++++++++- MotorControl/commands.h | 7 +++++++ Src/freertos.c | 3 +++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/MotorControl/commands.c b/MotorControl/commands.c index c90579c3..6e371649 100644 --- a/MotorControl/commands.c +++ b/MotorControl/commands.c @@ -2,6 +2,7 @@ #include #include #include +#include #include extern PCD_HandleTypeDef hpcd_USB_OTG_FS; @@ -10,12 +11,16 @@ extern PCD_HandleTypeDef hpcd_USB_OTG_FS; /* Private typedef -----------------------------------------------------------*/ /* Global constant data ------------------------------------------------------*/ /* Global variables ----------------------------------------------------------*/ -// For now, this automatically updates to the interface that most +// This automatically updates to the interface that most // recently recieved a command. In the future we may want to separate // debug printf and the main serial comms. SerialPrintf_t serial_printf_select = SERIAL_PRINTF_IS_NONE; /* Private constant data -----------------------------------------------------*/ +// TODO: make command to switch gpio_mode during run-time +static const GpioMode_t gpio_mode = GPIO_MODE_UART; //GPIO 1,2 is UART Tx,Rx +// static const GpioMode_t gpio_mode = GPIO_MODE_STEP_DIR; //GPIO 1,2 is M0 Step,Dir + // variables exposed to usb/serial interface via set/get/monitor // Note: this will be depricated soon static float* const exposed_floats[] = { @@ -114,6 +119,17 @@ monitoring_slot monitoring_slots[20] = {0}; static void print_monitoring(int limit); /* Function implementations --------------------------------------------------*/ +void init_communication() { + switch (gpio_mode) { + case GPIO_MODE_UART: { + SetGPIO12toUART(); + } break; + case GPIO_MODE_STEP_DIR: { + SetGPIO12toStepDir(); + } + } +} + void motor_parse_cmd(uint8_t* buffer, int len, SerialPrintf_t response_interface) { // Set response interface serial_printf_select = response_interface; diff --git a/MotorControl/commands.h b/MotorControl/commands.h index a23756b8..1483af9c 100644 --- a/MotorControl/commands.h +++ b/MotorControl/commands.h @@ -4,6 +4,12 @@ /* Includes ------------------------------------------------------------------*/ #include /* Exported types ------------------------------------------------------------*/ + +typedef enum { + GPIO_MODE_UART, + GPIO_MODE_STEP_DIR, +} GpioMode_t; + typedef enum { SERIAL_PRINTF_IS_NONE, SERIAL_PRINTF_IS_USB, @@ -17,6 +23,7 @@ extern SerialPrintf_t serial_printf_select; /* Exported functions --------------------------------------------------------*/ /* Exported functions --------------------------------------------------------*/ +void init_communication(); void cmd_parse_thread(void const * argument); void motor_parse_cmd(uint8_t* buffer, int len, SerialPrintf_t response_interface); diff --git a/Src/freertos.c b/Src/freertos.c index 62d3a451..d9295ff5 100644 --- a/Src/freertos.c +++ b/Src/freertos.c @@ -120,6 +120,9 @@ void StartDefaultTask(void const * argument) /* USER CODE BEGIN StartDefaultTask */ + // Init communications + init_communication(); + // Init motor control init_motor_control(); From 4381e052e2dbb7868e3ab299d85894875151dedd Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sat, 14 Oct 2017 19:18:11 -0700 Subject: [PATCH 35/35] add instructions about UART --- CHANGELOG.md | 6 ++++++ README.md | 33 +++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b9b4455..fa0e055b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +## [0.2.0] - UNRELEASED +### Added +* UART feature +* Setting to select UART or Step/dir on GIPIO 1,2 +### Changed + ## [0.1.0] - 2017-08-26 ### Added * Step/Dir interface diff --git a/README.md b/README.md index 11438531..259e9c1c 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ There is also [ODriveFPGA](https://github.com/madcowswe/ODriveFPGA), which conta - [Configuring parameters](#configuring-parameters) - [Compiling and downloading firmware](#compiling-and-downloading-firmware) -- [Communicating over USB](#communicating-over-usb) +- [Communicating over USB and UART](#communicating-over-usb-and-uart) - [Generating startup code](#generating-startup-code) - [Setting up Eclipse development environment](#setting-up-eclipse-development-environment) - [Notes for Contributors](#notes-for-contributors) @@ -25,24 +25,33 @@ There is also [ODriveFPGA](https://github.com/madcowswe/ODriveFPGA), which conta ## Configuring parameters To correctly operate the ODrive, you need to supply some parameters. Some are mandatory, and if supplied incorrectly will cause the drive to malfunction. To get good performance you must also tune the drive. +### Hardware configuration The first thing to set is your board hardware version, located at the top of [Inc/main.h](https://github.com/madcowswe/ODriveFirmware/blob/master/Inc/main.h). If, for example, you are using the hardware: ODrive v3.2, then you should set it like this: ```C #define HW_VERSION_MAJOR 3 #define HW_VERSION_MINOR 2 ``` +### Communication configuration +If you are using USB only to communicate with the ODrive, you may skip this step. + +The GPIO 1,2 pins are configurable as either step/direction, or as UART. +In [MotorControl/commands.c](https://github.com/madcowswe/ODriveFirmware/blob/master/MotorControl/commands.c) please set `gpio_mode` to the corresponding value (`GPIO_MODE_UART` or `GPIO_MODE_STEP_DIR`). + + +### Motor control parameters The rest of all the parameters are at the top of the [MotorControl/low_level.c](https://github.com/madcowswe/ODriveFirmware/blob/master/MotorControl/low_level.c) file. Please note that many parameters occur twice, once for each motor. In it's current state, the motor structs contain both tuning parameters, meant to be set by the developer, and static variables, meant to be modified by the software. Unfortunatly these are mixed together right now, but cleaning this up is a high priority task. It may be helpful to know that the entry point of each of the motor threads is `void motor_thread` at the bottom of [MotorControl/low_level.c](https://github.com/madcowswe/ODriveFirmware/blob/master/MotorControl/low_level.c). This is like `main` for each motor, and is probably where you should start reading the code. -### Mandatory parameters +#### Mandatory parameters You must set: * `ENCODER_CPR`: Encoder Count Per Revolution (CPR). This is 4x the Pulse Per Revolution (PPR) value. * `POLE_PAIRS`: This is the number of magnet poles in the rotor, divided by two. You can simply count the number of magnets in the rotor, if you can see them. * `brake_resistance`: This is the resistance of the brake resistor. If you are not using it, you may set it to 0.0f. -### Tuning parameters +#### Tuning parameters The most important parameters are the limits: * The current limit: `.current_lim = 75.0f, //[A] // Note: consistent with 40v/v gain`. The default current limit, for safety reasons, is set to 10A. This is quite weak, and good for making sure the drive is stable. Once you have tuned the drive, you can increase this to 75A to get some performance. Note that above 75A, you must change the current amplifier gains. * The velocity limit: `.vel_limit = 20000.0f, // [counts/s]`. Does what it says on the tin. @@ -61,7 +70,7 @@ An upcoming feature will enable automatic tuning. Until then, here is a rough tu * Back down `pos_gain` until you do not have overshoot anymore. * The integrator is not easily tuned, nor is it strictly required. Tune at your own discression. -### Optional parameters +#### Optional parameters By default both motors are enabled, and the default control mode is position control. If you want a different mode, you can change `.control_mode`. To disable a motor, set `.enable_control` and `.do_calibration` to false. @@ -106,7 +115,7 @@ After installing all of the above, open a Git Bash shell. Continue at section [B Run `make gdb`. This will reset and halt at program start. Now you can set breakpoints and run the program. If you know how to use gdb, you are good to go. If you prefer to debug from eclipse, see [Setting up Eclipse development environment](#setting-up-eclipse-development-environment). -## Communicating over USB +## Communicating over USB and UART There is currently a very primitive method to read/write configuration, commands and errors from the ODrive over the USB. Please use the `ODriveFirmware/tools/test_bulk.py` python script for this. It is written for Python 3. @@ -118,7 +127,13 @@ Setup instructions as follows: * Run test_bulk.py ### Command set -The most accurate way to understand the commands is to read [the code](https://github.com/madcowswe/ODriveFirmware/blob/f19f1b78de4bd917284ff95bc61ca616ca9bacc4/MotorControl/low_level.c#L353) that parses the commands. +The most accurate way to understand the commands is to read [the code](https://github.com/madcowswe/ODriveFirmware/blob/f19f1b78de4bd917284ff95bc61ca616ca9bacc4/MotorControl/vommands.c#L133) that parses the commands. Nevertheless, here is an overview: + +#### UART framing +USB communicates with packets, so it is easy to frame a command as one command per packet. However, UART doesn't have any packeting, so we need a way to frame the commands. The start-of-packet symbol is `$` and the end-of-packet symbol is `!`, that is, something like this: `$command!`. An example of a valid UART position command: +``` +$p 0 10000 0 0! +``` #### Motor Position command ``` @@ -191,12 +206,6 @@ We also use a tool to generate the Makefile. The steps to do this are as follows * Press `Project -> Generate code` * You may need to let it download some drivers and such. -### Generate makefile -There is an excellent project called CubeMX2Makefile, originally from baoshi. This project is included as a submodule. -* Initialise and clone the submodules: `git submodule init; git submodule update` -* Generate makefile: `python2 CubeMX2Makefile/CubeMX2Makefile.py .` - - ## Setting up Eclipse development environment ### Install