방법이 어렵지 않아서 금방 테스트가 끝났는데, STM32F446 에서는 DMA를 사용하면 f_mount() 함수에서 멈춰버렸습니다.
DMA를 사용할 경우 sd_diskio.c 의 SD_read 함수 내의
BSP_SD_ReadBlocks() 함수를 BSP_SD_ReadBlocks_DMA() 함수로 바꿔주면 됩니다.
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
|
/**
* @brief Reads Sector(s)
* @param lun : not used
* @param *buff: Data buffer to store read data
* @param sector: Sector address (LBA)
* @param count: Number of sectors to read (1..128)
* @retval DRESULT: Operation result
*/
DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
{
DRESULT res = RES_OK;
/*if(BSP_SD_ReadBlocks((uint32_t*)buff,
(uint64_t) (sector * BLOCK_SIZE),
BLOCK_SIZE,
count) != MSD_OK)*/
if(BSP_SD_ReadBlocks_DMA((uint32_t*)buff,
(uint64_t) (sector * BLOCK_SIZE),
BLOCK_SIZE,
count) != MSD_OK)
{
res = RES_ERROR;
}
return res;
}
/**
* @brief Writes Sector(s)
* @param lun : not used
* @param *buff: Data to be written
* @param sector: Sector address (LBA)
* @param count: Number of sectors to write (1..128)
* @retval DRESULT: Operation result
*/
#if _USE_WRITE == 1
DRESULT SD_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
{
DRESULT res = RES_OK;
/*if(BSP_SD_WriteBlocks((uint32_t*)buff,
(uint64_t)(sector * BLOCK_SIZE),
BLOCK_SIZE, count) != MSD_OK)*/
if(BSP_SD_WriteBlocks_DMA((uint32_t*)buff,
(uint64_t)(sector * BLOCK_SIZE),
BLOCK_SIZE, count) != MSD_OK)
{
res = RES_ERROR;
}
return res;
}
| cs |
STM32F446 Nucleo 보드에서 DMA를 사용하지 않으면 동작은 잘 되는데,
가끔 Error이 발생해서 SD-Card 와의 선을 짧게 하니 잘 동작 했습니다.
보드의 아트웍 영향인건지는 확실히 모르겠는데, 배선도 좀 짧으면 좋은 것 같습니다.
이 상태로 13KByte 의 데이터를 읽는데 10ms 정도의 시간이 걸렸으니
거의 1MB/sec 의 속도밖에 안나와서 SDIO를 왜 쓰나 싶더군요.
그래서 처음부터 다시 프로젝트를 만들어서 동작을 시켜봤는데, 역시나 결과는 DMA 기능은 구현이 안되네요.
그런데, 뭔가 틀려진 점이 있는데, DMA를 안 썼을 때 13KB를 읽는데 10ms 걸렸던 것이 2ms 로 대폭 줄었습니다.
24KB를 읽었더니 3ms 고요. 마치 DMA가 동작되는 듯이 느껴질 정도로 빨라졌지만 DMA는 동작되지 않는 상황.
빨라진 이유는 제가 코드를 잘 못 만들어서 그렇네요. f_read()함수가 512 Byte씩 읽어야 되는 줄 알고 24K 파일을
512Byte 단위로 f_read()함수를 이용해 여러번 나눠서 읽었더니 느리고 한번에 24KB를 다 읽으니 빠르네요.
예전에 테스트를 했을 때, 512-Byte 이상 읽으면 안 읽혔었는데 이번에 해 보니 한번에 많은 데이터도 읽기 가능하네요.
[512 Byte 씩 여러번 읽어서 느렸던 코드내용]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
uint8_t read_f_dat(uint8_t *pf_dat,FIL* fp)
{
UINT i,testBytes;
uint32_t f_size;
f_size = 13000;
// #define _MAX_SS 512
for (i=0;i<f_size;i+=_MAX_SS)
{
if ((f_size - i) < _MAX_SS)
{
res = f_read(fp, &pf_dat[i],(f_size - i), &testBytes);
}
else
{
res = f_read(fp, &pf_dat[i],_MAX_SS, &testBytes);
}
}
}
| cs |
[한번에 많은 데이터를 읽어서 빨라지도록 수정된 코드]
1
2
3
4
5
6
7
8
9
|
uint8_t read_f_dat(uint8_t *pf_dat,FIL* fp)
{
UINT testBytes;
uint32_t f_size;
f_size = 13000;
res = f_read(fp, &pf_dat[0],f_size, &testBytes);
}
| cs |
아뭏든 현재 첨부한 프로젝트는 DMA는 동작이 안되는 것으로 보이고, 계속해서 방법을 찾아보다가
잘 되면 DMA SDIO-4bit 관련 글을 다시 올려 보겠습니다.
다음은 Nucleo - STM32F446 보드에서 DMA가 안되서 새로 프로젝트를 만들었던 과정입니다.
3. SDIO 를 DMA 로 동작하도록 CUBEMX 에서 설정.
4. sd_diskio.c 파일에서 SD_read/SD_write 함수 안의 BSP_SD_ReadBlocks/BSP_SD_WriteBlocks 함수를 바꾸지 않고 그대로 사용했는데 24KB 읽는데 걸리는 시간이 3ms 걸렸음.
5. 혹시 다 읽힌 것 맞는지 알아보려고 해리포터 소설을 UART로 뿌려보니 제대로 읽혀 있었습니다.
SDIO는 많은 양을 읽을수록 속도가 점점 더 빨라지는 듯 합니다.
그리고 STM32F411 은 42MHz 로도 DMA가 동작하는데, STM32F446 은 45MHz로 일반 방식에서는 동작하지 않았습니다.
(차후 DMA 구현되면 다시 비교해 볼 예정)
[STM32F4xx 에서 SDIO CLK를 최대(411:42MHz,446:45MHz)로 설정한 코드 내용]
1
2
3
4
5
6
7
8
9
10
11
12
|
/* SDIO init function */
static void MX_SDIO_SD_Init(void)
{
hsd.Instance = SDIO;
hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_ENABLE;
hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
hsd.Init.ClockDiv = 0;
}
| cs |
STM32F446 이 DMA가 안된 상태에서 비교를 하니 의미가 많이 없지만,
또한 411은 SDIO_CLK=42MHz 이고 446은 22.5MHz 이기때문에,
이 상태에서는 (당연하게도)STM32F411 이 더 빨랐습니다.
STM32F446(SDIO_CLK:22.5MHz)은 13KB 읽는데 2ms, 24KB 3ms가 걸렸는데,
STM32F411(SDIO_CLK:42MHz) 은 13KB/1.4ms , 24KB/2ms 밖에 안걸립니다.
24KB 읽는 것을 기준으로 STM32F411 은 최대 속도 12MB/s , STM32F446 은 최대속도 8MB/s 나오네요.
이 속도는 앞서서도 말씀 드렸듯이 한번에 많이 읽으면 더 빨라집니다.
6. 해리포터 소설을 24KB 만큼 읽어서 출력해 봄.
7. main() 주요 동작 코드
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_SDIO_SD_Init();
MX_USART2_UART_Init();
MX_FATFS_Init();
/* USER CODE BEGIN 2 */
read_TAR_file_DMA();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/* SDIO init function */
static void MX_SDIO_SD_Init(void)
{
hsd.Instance = SDIO;
hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
//hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_ENABLE;
hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
hsd.Init.ClockDiv = 0;
}
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA2_CLK_ENABLE();
/* DMA interrupt init */
/* DMA2_Stream3_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
/* DMA2_Stream6_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);
}
/* USER CODE BEGIN 4 */
void read_TAR_file_DMA(void)
{
#if _USE_LFN
TCHAR lfn[_MAX_LFN + 1];
fno_t.lfname = lfn;
fno_t.lfsize = sizeof lfn;
#endif
BYTE testBuffer[24000];
uint8_t path[13];
DWORD cnt_rd_Byte=24000;
UINT testBytes;
DWORD cnt_i;
UINT i,cnt_512;
uint32_t image_offset;
//sprintf(path,"1.tar");
sprintf(path,"aaa.txt");
printf("%s\n\r",path);
res_t = f_mount(&fs32_t,SD_Path,1);
printf("SD Mount : res f_mount : %02X\n\r",res_t);
res_t = f_open(&fil_t, (char*)path, FA_READ);
printf("res f_open : %02X, fil_t.fsize : %d\n\r",res_t,fil_t.fsize);
printf("Read Txt File Test\n\r");
GPIOB->ODR ^= GPIO_PIN_5;
res_t = f_read(&fil_t, testBuffer, cnt_rd_Byte, &testBytes);
GPIOB->ODR ^= GPIO_PIN_5;
printf("res_t = f_read : %02X\n\r",res_t);
for(i=0;i<24000;i++)
printf("%c",testBuffer[i]);
}
/* USER CODE END 4 */
| cs |
추가로 DMA 인터럽트도 DMA 동작이 안되는 것과 관련이 있을 수도 있다 싶어서 인터럽트 설정 부분도 올려 봅니다.
혹시 왜 DMA가 안되는지 아시는분 알려주시면 대단히 고맙겠습니다.
아래와 같이 인터럽트를 여러가지로 변경해 봤는데, DMA 동작은 여전히 안됐습니다.
그런데 DMA를 사용하지 않아도 SDIO_CLK 22.5MHz의 속도로써 늦은 속도는 아닌 것 같습니다.
(STM32F411 SDIO_CLK 42MHz(DMA)에서 13KB 전송시 1.4ms 이고, STM32F446 SDIO_CLK 22.5MHz(No DMA) 에서 2ms 걸렸기 때문에)
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
|
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA2_CLK_ENABLE();
/* DMA interrupt init */
/* DMA2_Stream3_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
/* DMA2_Stream6_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);
}
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA2_CLK_ENABLE();
/* DMA interrupt init */
/* DMA2_Stream3_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
/* DMA2_Stream6_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);
}
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA2_CLK_ENABLE();
/* DMA interrupt init */
/* DMA2_Stream3_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
/* DMA2_Stream6_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);
}
| cs |
댓글 없음:
댓글 쓰기