# STM32F429 UART & CAN bus 整合
###### tags: `Internship`,`NSPO`
[TOC]
## Final Project Report
簡介工作細節
:::success
我負責為XTx資料傳輸,XTx在衛星電機次系統功能為向基地台傳送資料,並接受EUCC指令,此6U衛星為傳送圖像資料為主,以下為XTx在本實作整體程序(mode2-3)。
**註解:** 本說明為 **LOOPBACKMODE** 因此未與EUCC連接,是STM32自傳自收
:::

## 工作環境
* OS : Windows 10
* IDE: eclipse(luna版本)
* 燒錄軟體: 內建ST-Link
* Terminal: hercules_3-2-8.exe
* 開發板:STM32F429 Discovery kit
:::danger
**最終目標 :** 實現CAN bus自傳自收(指令字串)並使用UART與電腦回應狀態。
:::
## 成果截圖(Terminal):

## 1. XTx 簡介 (X-Band Transmitter)
1. 高速資料傳輸 (10 Mbit/s以上)
2. 使用 X 頻段 (8175 – 8215 MHz)
3. 下傳經過壓縮與編碼後的資料至地面基地台
## 2. 本實作流程 (LOOPBACK MODE)

## 3. 本實作程序說明 (LOOPBACK MODE)
將依續說明需要撰寫的程式碼:
### (1) Receive user command using **UART RX_interrupt**
:::warning
**提醒** :以下啟動函式需要放入`while(1)`迴圈內,才可持續接收CPU指令。
:::
1. `main.c`:
``` C=
if(HAL_UART_Receive_IT(&UartHandle (uint8_t*) aRxBuffer, RXBUFFERSIZE)!= HAL_OK)
{
//Error_Handler();
}
```
要注意的是:根據`RXBUFFERSIZE`決定**輸入資料長度**,若長度**小於**Size,則會繼續等待接收,最終會時間超過,很可能會return `HAL_Timeout`因此在一開始有提醒,只能輸入poweron或poweroff,在此專案長度為 **7 bytes**。
2. `HAL_UART_OUT.h`:
```c=
#define TXBUFFERSIZE (7)//Unit:byte
```
### (2) Send data to Earth Station using **RxCallback**
(also print messages on terminal to inform user.)
:::info
在`HAL_UART_OUT.c`的`HAL_UART_RxCpltCallback`中:將extern的UART_Rx_flag設成1,回到main.c中CPU會進入以下程式碼進行印出poweron動作並flag=1去執行**用CAN BUS傳送資料給地面台**
:::
:::danger
**注意** :在中斷底層盡量不要進行動作,如DELAY與print,理由如下:
1.中斷內的時間非同步主程式時間。
2.UART中斷也是使用同個暫存器,因此不適合在底層使用print()。
:::
1. `HAL_UART_OUT.c`:
```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 */
}
```
2. 在`HAL_UART_out.c`的`STM32f4_UART_Init(UART_HandleTypeDef *huart)`內補上:
``` C=
//=============
/* NVIC configuration for USART TC interrupt */
HAL_NVIC_SetPriority(USART1_IRQn, 6, 2);
HAL_NVIC_EnableIRQ(USART1_IRQn);
//=============
```
代表收到進入中斷
3. Terminal 收到開機指令(power on)->(UART_Rx_flag設成1)進行回報(power on)動作
`main.c`:
```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;
}
```
4. CAN_flag=1時CPU會透過**CAN bus**傳送給地面台(正在傳送DATA)
`main.c`:
```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);
}
}
```
5. CAN reciever收到訊息後會進入`CAN1_RX0_IRQHandler`並到`HAL_CAN_RxCpltCallback`進行動作
`stm32f4xx_it.c`:
```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
:::warning
**注意** :以下啟動函式需要放入`HAL_CAN_RxCpltCallback`,中斷執行結束後,需重複開啟中斷。
:::
```c=
if(HAL_CAN_Receive_IT(&CanHandle, CAN_FIFO0) != HAL_OK)
{
/* Reception Error */
Error_Handler();
}
```
* Step2. In `stm32f4xx_it.c`:
```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`:
```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`檔案:
```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. 其他初始化或細節注意
:::warning
**提醒**:
在使用模擬的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`:
```C=
#define CAN_TRANSMIT_UNLOCK (1)
#define CAN_RECEIVE_IRQ_UNLOCK (1)
```
### 附錄:`print("str")` using UART
```c=
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`