쿼드콥터를 만들 때 많은 센서들은 SPI가 아닌 I2C를 사용했다. 그렇기 때문에 많이 사용하지 않은 통신이다.
하지만 PID 값을 저장하기 위한 FLASH Memory제어, nrf24l01 통신 모듈을 사용하기 위해서 SPI 통신을 해야 했다.
HAL드라이버의 HAL_SPI_Transmit(), HAL_SPI_Receive(), HAL_TransmitReceive() 3개의 함수와 대응되는 3개의 함수를 LL 드라이버로 코드를 작성한 후 W25Q16 FLASH Memory에 데이터를 읽고 쓰는 코드까지 작성해 보겠다.
SPI 코드 생성 (0)
SPI Mode는 Full Duplex Master 이며, 데이터를 보내면서 데이터를 받을 수 있는 모드이다.
예를 들어 nrf24l01 SPI 통신 과정을 보면 Master에서 Slave로 커맨드를 보낼 때 Slave에서 STATUS register데이터를 Master로 보내 Master가 데이터를 동시에 읽을 수 있다.
코드 - TXRX (1)
Full Duplex 모드에서 데이터를 쓰고 읽는 과정을 동시에 하는 흐름을 보여준다.
데이터시트를 참고하여 코드를 작성했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
void SPI_TransmitReceive(SPI_TypeDef *SPI,uint8_t* output,uint8_t* input, uint16_t size){
LL_SPI_SetTransferDirection(SPI,LL_SPI_FULL_DUPLEX);
if(!LL_SPI_IsEnabled(SPI)){
LL_SPI_Enable(SPI);
}
for(uint16_t i=0;i<size;i++){
while(!LL_SPI_IsActiveFlag_TXE(SPI));
LL_SPI_TransmitData8(SPI,output[i]);
while(!LL_SPI_IsActiveFlag_RXNE(SPI));
input[i]=LL_SPI_ReceiveData8(SPI);
}
while(LL_SPI_IsActiveFlag_BSY(SPI));
}
|
TX와 RX 동시에 주고받을 수 있다.
코드 - TX ONLY (2)
다른 통신들과 마찬가지로 데이터시트를 분석해서 코드를 작성하기만 하면 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
void SPI_Transmit(SPI_TypeDef *SPI,uint8_t* output,uint16_t size){
LL_SPI_SetTransferDirection(SPI,LL_SPI_FULL_DUPLEX);
if(!LL_SPI_IsEnabled(SPI)){
LL_SPI_Enable(SPI);
}
for(uint16_t i=0;i<size;i++){
while(!LL_SPI_IsActiveFlag_TXE(SPI));
LL_SPI_TransmitData8(SPI,output[i]);
}
while(LL_SPI_IsActiveFlag_BSY(SPI));
if(LL_SPI_IsActiveFlag_RXNE(SPI)){
LL_SPI_ReceiveData8(SPI);
}
}
|
Full Duplex 모드에서 데이터를 받지 않고 데이터를 쓰기만 할 때 사용한다.
이때 마지막에 SPI_DS Register를 읽어 혹시라도 받은 데이터에 의한 RXNE flag를 RESET시킨다.
코드 - RX ONLY (3)
1
2
3
|
void SPI_Receive(SPI_TypeDef *SPI,uint8_t* input,uint16_t size){
SPI_TransmitReceive(SPI,input,input,size);
}
|
HAL코드를 분석해본 결과 따로 Recieve코드를 만들지 않고 TransmitReceive 함수를 불러 데이터를 받는다.
따라서 SPI_TransmitReceive로 Receive 함수를 구현했다.
1
2
3
4
5
6
7
8
9
10
11
12
|
void SPI_Receive(SPI_TypeDef *SPI, uint8_t* input, uint16_t size){
if(!LL_SPI_IsEnabled(SPI)){
LL_SPI_Enable(SPI);
}
LL_SPI_SetTransferDirection(SPI,LL_SPI_SIMPLEX_RX);
for(uint16_t i=0;i<size;i++){
while(!LL_SPI_IsActiveFlag_RXNE(SPI));
input[i]=LL_SPI_ReceiveData8(SPI);
}
LL_SPI_SetTransferDirection(SPI,LL_SPI_FULL_DUPLEX);
}
|
다른 코드도 작성했다. 하지만 실험 결과 문제점이 존재했는데, Baud Rate가 10MBits/s가 넘어가면 데이터가 밀려 제대로 된 데이터를 얻지 못했다.
SPI_Receive() 함수는 첫 번째 코드를 사용하는 것을 추천한다.
코드 - FLASH MEMORY (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
/* USER CODE BEGIN 2 */
uint8_t data[10];
printf("start\r\n");
data[0]=0x01;
data[1]=0x23;
data[2]=0x45;
data[3]=0x67;
data[4]=0x89;
data[5]=0xaa;
data[6]=0xbb;
data[7]=0xcc;
data[8]=0xdd;
data[9]=0xee;
flash_sector_erase(SPI1,0x0000);
flash_write(SPI1,0x0000,data,10);
data[0]=0xf1;
data[1]=0x2f;
data[2]=0xf5;
data[3]=0x6a;
data[4]=0x7f;
data[5]=0x7a;
data[6]=0xbf;
data[7]=0x5c;
data[8]=0x8d;
data[9]=0xe3;
flash_sector_erase(SPI1,0x1000);
flash_write(SPI1,0x1000,data,10);
for(int i=0;i<10;i++)
data[i]=0;
flash_read(SPI1,0x0000,data,10);
for(int i=0;i<10;i++){
printf("%.2x ",data[i]);
}
printf("\n\n\r");
for(int i=0;i<10;i++)
data[i]=0;
flash_read(SPI1,0x1000,data,10);
for(int i=0;i<10;i++){
printf("%.2x ",data[i]);
}
printf("\n\n\r");
/* USER CODE END 2 */
|
현재 사용하고 있는 개발 보드에 장착되어있는 W25Q16 Flash Memory이며 SPI1 핀들과 연결되어 있다.
Flash에 데이터를 쓰기 위해서는 해당 섹터를 한번 지워주고 써줘야 한다. 처음 코드를 짰을 때 이 사실을 몰라 몇 시간 동안 헤맨 기억이 난다.
flash_sector_erase()로 섹터를 지우고 flash_write()로 데이터를 쓴 후 두 함수들을 지우고 다시 빌드하여 MCU에 프로그램을 올려도 flash_read() 함수로 데이터를 읽어 값들이 출력된다.
작성된 코드를 분석하고 Flash의 데이터시트를 보면서 모르는 부분은 참고하면 될 것이다.
-
헥사콥터를 제작하기 위한 통신 UART, I2C, SPI에 대한 내용이 드디어 끝났다.
SPI 통신은 Flash Memory에 pid값들에 대한 정보를 수정하고 가져오기 위해 많이 사용한다.
또한 nrf24l01 통신 모듈과 통신할 때 사용된다.
인터럽트와 DMA는 실제 코드를 작성할 때 필요하면 추가할 생각이다.
'임베디드 > STM32' 카테고리의 다른 글
[STM32] LL 드라이버 - ADC, DAC, DMA (0) | 2020.07.27 |
---|---|
[STM32] LL 드라이버 - I2C DMA로 작성한 MPU6050 상보필터 (1) | 2020.07.19 |
[STM32] CubeMX LL 드라이버 - I2C (3) (0) | 2020.07.15 |
[STM32] CubeMX LL 드라이버 - UART RX (2) (0) | 2020.07.13 |
[STM32] CubeMX LL 드라이버 - UART TX (1) (0) | 2020.07.13 |