Try   HackMD

STM32F429 UART & CAN bus 整合

tags: Internship,NSPO

Final Project Report

簡介工作細節

我負責為XTx資料傳輸,XTx在衛星電機次系統功能為向基地台傳送資料,並接受EUCC指令,此6U衛星為傳送圖像資料為主,以下為XTx在本實作整體程序(mode2-3)。
註解: 本說明為 LOOPBACKMODE 因此未與EUCC連接,是STM32自傳自收

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

工作環境

  • OS : Windows 10
  • IDE: eclipse(luna版本)
  • 燒錄軟體: 內建ST-Link
  • Terminal: hercules_3-2-8.exe
  • 開發板:STM32F429 Discovery kit

最終目標 : 實現CAN bus自傳自收(指令字串)並使用UART與電腦回應狀態。

成果截圖(Terminal):

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

1. XTx 簡介 (X-Band Transmitter)

  1. 高速資料傳輸 (10 Mbit/s以上)
  2. 使用 X 頻段 (8175 – 8215 MHz)
  3. 下傳經過壓縮與編碼後的資料至地面基地台

2. 本實作流程 (LOOPBACK MODE)

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

3. 本實作程序說明 (LOOPBACK MODE)

將依續說明需要撰寫的程式碼:

(1) Receive user command using UART RX_interrupt

提醒 :以下啟動函式需要放入while(1)迴圈內,才可持續接收CPU指令。

  1. main.c
if(HAL_UART_Receive_IT(&UartHandle (uint8_t*) aRxBuffer, RXBUFFERSIZE)!= HAL_OK) { //Error_Handler(); }

要注意的是:根據RXBUFFERSIZE決定輸入資料長度,若長度小於Size,則會繼續等待接收,最終會時間超過,很可能會return HAL_Timeout因此在一開始有提醒,只能輸入poweron或poweroff,在此專案長度為 7 bytes

  1. HAL_UART_OUT.h
#define TXBUFFERSIZE (7)//Unit:byte

(2) Send data to Earth Station using RxCallback

(also print messages on terminal to inform user.)

HAL_UART_OUT.cHAL_UART_RxCpltCallback中:將extern的UART_Rx_flag設成1,回到main.c中CPU會進入以下程式碼進行印出poweron動作並flag=1去執行用CAN BUS傳送資料給地面台

注意 :在中斷底層盡量不要進行動作,如DELAY與print,理由如下:
1.中斷內的時間非同步主程式時間。
2.UART中斷也是使用同個暫存器,因此不適合在底層使用print()。

  1. HAL_UART_OUT.c
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { /* Set transmission flag: transfer complete*/ //UsartReady_0 = SET; UsartReady_Rx = SET; UART_Rx_flag = 1; /*只UART_Rx收到訊息*/ /* Turn LED4 on: Transfer in reception process is correct */ }
  1. HAL_UART_out.cSTM32f4_UART_Init(UART_HandleTypeDef *huart)內補上:
//============= /* NVIC configuration for USART TC interrupt */ HAL_NVIC_SetPriority(USART1_IRQn, 6, 2); HAL_NVIC_EnableIRQ(USART1_IRQn); //=============

代表收到進入中斷

  1. Terminal 收到開機指令(power on)->(UART_Rx_flag設成1)進行回報(power on)動作

main.c

if(UART_Rx_flag == 1) { if(aRxBuffer[6]==0x6E) { print_string("power on\r\n"); flag = 1; } else { print_string("power off"); } UART_Rx_flag = 0; }
  1. CAN_flag=1時CPU會透過CAN bus傳送給地面台(正在傳送DATA)

main.c

if(flag == 1) { press_cnt = 0; CanHandle.pTxMsg->StdId = 0x302; CanHandle.pTxMsg->IDE = CAN_ID_STD; CanHandle.pTxMsg->DLC = 1; CanHandle.pTxMsg->Data[0] = TelID(0X01,0X01); if(HAL_CAN_Transmit(&CanHandle, 10) != HAL_OK)//ms { } press_cnt = 0; print_string("CAN TX(0x302):\r\n"); print_u32x(CanHandle.pTxMsg->StdId); if(CAN_flag==1) { BSP_LED_On(LED3); print_string("CAN RX(0x302):\r\n"); print_u32x(CanHandle.pRxMsg->StdId); print_string("DATA Loading.\r\n"); print_string("flag:"); print_u8x(flag); HAL_Delay(1000); BSP_LED_Off(LED3); } }
  1. CAN reciever收到訊息後會進入CAN1_RX0_IRQHandler並到HAL_CAN_RxCpltCallback進行動作

stm32f4xx_it.c

void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef *hcan) { static int digitStatus = 1; if(hcan->pRxMsg->StdId ==0x302) { CAN_flag = 1; flag = 2; } }

注意要開啟中斷分別要有以下兩步驟(CAN bus)

  • Step1. In main.c,enable HAL_CAN_Receive_IT

注意 :以下啟動函式需要放入HAL_CAN_RxCpltCallback,中斷執行結束後,需重複開啟中斷。

if(HAL_CAN_Receive_IT(&CanHandle, CAN_FIFO0) != HAL_OK) { /* Reception Error */ Error_Handler(); }
  • Step2. In stm32f4xx_it.c
void CAN1_RX0_IRQHandler(void) { // Get data from CAN HAL_CAN_IRQHandler(&CanHandle); }

(3) When data loading over use CAN Transmit and CAN Reciever

  1. CAN Transmit0x202 and CAN Reciever接收0x202並印出DATA loading over

main.c

if(flag == 2) { press_cnt = 0; CanHandle.pTxMsg->StdId = 0x202; CanHandle.pTxMsg->IDE = CAN_ID_STD; CanHandle.pTxMsg->DLC = 1; CanHandle.pTxMsg->Data[0] = TelID(0X03,0X00); if(HAL_CAN_Transmit(&CanHandle, 10) != HAL_OK)//10ms { } press_cnt = 0; print_string("CAN TX(0x202):\r\n"); print_u32x(CanHandle.pTxMsg->StdId); print_string("CAN RX(0x202):\r\n"); print_u32x(CanHandle.pTxMsg->StdId); print_string("DATA loading over.\r\n"); flag = 0; }

4. 實作

主要的main.c檔案:

/*我的主要code*/ STM32f4_UART_Init(&UartHandle); print_string("UART init done.\r\n"); STM32f4_CAN_Init(&CanHandle, &sFilterConfig, &TxMessage, &RxMessage); print_string("CAN init done.\r\n"); /* Turn LED3 on: Transfer in transmission process is correct */ /* then Off for next transmission */ BSP_LED_On(LED3); HAL_Delay(200); BSP_LED_Off(LED3); print_string("please insert poweron or poweroff.\r\n"); if(HAL_CAN_Receive_IT(&CanHandle, CAN_FIFO0) != HAL_OK) { /* Reception Error */ Error_Handler(); } if(HAL_UART_Receive_IT(&UartHandle, (uint8_t*)aRxBuffer, RXBUFFERSIZE)!= HAL_OK) { //Error_Handler(); } extern int UART_Rx_flag; while(1) { if(flag == 1) { press_cnt = 0; CanHandle.pTxMsg->StdId = 0x302; CanHandle.pTxMsg->IDE = CAN_ID_STD; CanHandle.pTxMsg->DLC = 1; CanHandle.pTxMsg->Data[0] = TelID(0X01,0X01); if(HAL_CAN_Transmit(&CanHandle, 10) != HAL_OK)//0ms { } press_cnt = 0; print_string("CAN TX(0x302):\r\n"); print_u32x(CanHandle.pTxMsg->StdId); if(CAN_flag==1) { BSP_LED_On(LED3); print_string("CAN RX(0x302):\r\n"); print_u32x(CanHandle.pRxMsg->StdId); print_string("DATA Loading.\r\n"); print_string("flag:"); print_u8x(flag); HAL_Delay(1000); BSP_LED_Off(LED3); } } if(flag == 2) { press_cnt = 0; CanHandle.pTxMsg->StdId = 0x202; CanHandle.pTxMsg->IDE = CAN_ID_STD; CanHandle.pTxMsg->DLC = 1; CanHandle.pTxMsg->Data[0] = TelID(0X03,0X00); // print_string("CAN TX SECOND:\r\n"); if(HAL_CAN_Transmit(&CanHandle, 10) != HAL_OK)//0ms { } press_cnt = 0; print_string("CAN TX(0x202):\r\n"); print_u32x(CanHandle.pTxMsg->StdId); print_string("CAN RX(0x202):\r\n"); print_u32x(CanHandle.pTxMsg->StdId); print_string("DATA loading over.\r\n"); flag = 0; } if(UART_Rx_flag == 1) { if(aRxBuffer[6]==0x6E) { print_string("power on\r\n"); flag = 1; } else { print_string("power off"); } UART_Rx_flag = 0; } } /*我的主要code*/

5. 其他初始化或細節注意

提醒
在使用模擬的Terminal console時:
1.baurate (此範例為9600)
2.STOP bit(此範例為1)
3.Parity bit(此範例為None)
設定要跟UART_Init()內的設定一樣才能有效!
////
4.Tx傳送尚未結束即會進行Rx中斷(因為中斷優先權較高),又在Rx中斷下又開Receive,因此Tx和Rx Receive會互鎖,因此修正方式即是將互鎖機制取消。

互鎖設定取消HAL_CAN_INIT.h

#define CAN_TRANSMIT_UNLOCK (1) #define CAN_RECEIVE_IRQ_UNLOCK (1)

附錄:print("str") using UART

void print_u8x(uint8_t int8){ uint8_t print_cnt=0; sprintf(UsartTxBuffer_0, "0x%02X\r\n", int8); while(UsartTxBuffer_0[print_cnt]!='\0'){print_cnt++;} HAL_UART_Transmit(&UartHandle, (uint8_t*)UsartTxBuffer_0, print_cnt, 5000); } void print_u32x(unsigned int int32){ uint8_t print_cnt=0; sprintf(UsartTxBuffer_0, "0x%08X\r\n", int32); while(UsartTxBuffer_0[print_cnt]!='\0'){print_cnt++;} HAL_UART_Transmit(&UartHandle, (uint8_t*)UsartTxBuffer_0, print_cnt, 5000); } void print_string_DMA(char str[]){ uint8_t print_cnt=0; sprintf(UsartTxBuffer_0, "%s", str); while(UsartTxBuffer_0[print_cnt]!='\0'){print_cnt++;} HAL_UART_Transmit_DMA(&UartHandle, (uint8_t*)UsartTxBuffer_0, print_cnt); while (UsartReady_0 != SET){} UsartReady_0 = RESET;
tags: NSPO