реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Чтение STM32 из M25P64 по SPI при участии DMA, Как это правильно организовать?
011119xx
сообщение May 11 2011, 08:03
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 381
Регистрация: 5-07-05
Из: Уфа
Пользователь №: 6 544



Собственно говоря, что хочется понятно из названия темы. Уточню лишь, что хочу использовать SPI1 и судя по всему DMA1. В библиотеке периферии есть пример: SPI_RAM, но в нем используется 2 SPI, а мне бы только один хотелось. Как бы это сделать? Мои измышления привели к следующему порядку:
CODE
...
/* SPI_MASTER configuration ------------------------------------------------*/
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = CRCPolynomial;
SPI_Init(SPI_MASTER, &SPI_InitStructure);

/* SPI_MASTER_Rx_DMA_Channel configuration ---------------------------------*/
DMA_DeInit(SPI_MASTER_Rx_DMA_Channel);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SPI_MASTER_DR_Base;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SPI_MASTER_Buffer_Rx;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = BufferSize;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(SPI_MASTER_Rx_DMA_Channel, &DMA_InitStructure);

/* SPI_MASTER_Tx_DMA_Channel configuration ---------------------------------*/
DMA_DeInit(SPI_MASTER_Tx_DMA_Channel);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SPI_MASTER_DR_Base;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SPI_MASTER_Buffer_Tx;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
DMA_Init(SPI_MASTER_Tx_DMA_Channel, &DMA_InitStructure);

/* Enable SPI_MASTER DMA Tx request */
SPI_I2S_DMACmd(SPI_MASTER, SPI_I2S_DMAReq_Tx, ENABLE);
/* Enable SPI_MASTER DMA Rx request */
SPI_I2S_DMACmd(SPI_MASTER, SPI_I2S_DMAReq_Rx, ENABLE);

/* Enable SPI_MASTER CRC calculation */
SPI_CalculateCRC(SPI_MASTER, ENABLE);

/* Enable SPI_MASTER */
SPI_Cmd(SPI_MASTER, ENABLE);

/* Enable DMA channels */
DMA_Cmd(SPI_MASTER_Rx_DMA_Channel, ENABLE);
DMA_Cmd(SPI_MASTER_Tx_DMA_Channel, ENABLE);

/* Transfer complete */
while(!DMA_GetFlagStatus(SPI_MASTER_Rx_DMA_FLAG));
while(!DMA_GetFlagStatus(SPI_MASTER_Tx_DMA_FLAG));

... а что дальше?


Сообщение отредактировал IgorKossak - Feb 1 2012, 11:56
Причина редактирования: [codebox]
Go to the top of the page
 
+Quote Post
akimych
сообщение May 11 2011, 21:45
Сообщение #2


Участник
*

Группа: Участник
Сообщений: 72
Регистрация: 7-01-11
Пользователь №: 62 073



В примере 2 SPI используюются, т.к. они гоняют байты из одного SPI в другой. А иначе ест-но только один канал нужен - мастер. Слейвом будет M25P64.
Инициализация уже есть (до /* Enable DMA channels */).
Передача - настраиваем дма (адрес, длина буфера, при выключеном канале) и в ключаем канал. Ждем окончания передачи.
С приемом тоже настраиваем, а потом возможно 2 варианта. Т.к. для приема нужно выдать клок, то либо надо в цикле (или тоже через дма) отправлять что-нибудь, либо включить режим полудуплекс-прием, когда SPI сам будет непрерывно гнать клок, пока его не выключат.
Я использовал второй способ, в частности из-за того, что есть режим позволяющий сэкономить один вывод. Но столкнулся с такой особенностью, что при SPI_BaudRatePrescaler_2 и SPI_DataSize_8b иногда теряются байты. Объяснение у меня этому только одно - DMA не успевает вычитывать данные из SPI. Правда у меня еще АЦП через дма работает.
Go to the top of the page
 
+Quote Post
ISK2010
сообщение May 13 2011, 04:13
Сообщение #3


Местный
***

Группа: Участник
Сообщений: 205
Регистрация: 21-09-10
Из: г.Зеленоград
Пользователь №: 59 631



А я делаю так:
1) В фоне отправляю команду флэшке, а пока идет отправка настраиваю DMA на нужный буфер и количество байт.
2) После передачи последнего байта команды включаю DMATXE
3) После приема последнего байта ответа на команду включаю DMARXE
В обработчике прерывания по приему последнего байта DMA TC устанавливаю нужный флажок и произвожу "девыбор" флэшки
Go to the top of the page
 
+Quote Post
011119xx
сообщение May 13 2011, 05:37
Сообщение #4


Местный
***

Группа: Свой
Сообщений: 381
Регистрация: 5-07-05
Из: Уфа
Пользователь №: 6 544



А на код можно посмотреть?
Go to the top of the page
 
+Quote Post
Valentin-k
сообщение Jan 31 2012, 17:04
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 31
Регистрация: 27-01-12
Пользователь №: 69 923



а можно вопрос по теме!я вообще с флешками до этого не работал, а тут подключил к STM32 m25p64
все работает, записывает, читает...время записи совпадает с указанным в даташите...
но вот считывает информацию из памяти с той же скорость что и записывает - это правильно, мне коллеги говорят что чтение должно быть намного быстрее записи...с учетом что пины настроены на 50МГЦ...
ДМА не пробовал.
поэтому вопрос - возможно ли ускорить и вместо 400 мс на сектор, получить в районе 40-50 мс (при частоте 20МГЦ - по даташиту на флешку так написано)
и такой еще минивопросик - а обязательно при чтении постоянно слать Dummy byte, хотя без него чтение не происходит, но в том же даташите я не встречал чтобы писалось что перед каждым принимаемым байтом надо его отправлять...а в примерах - отправляют

Сообщение отредактировал Valentin-k - Jan 31 2012, 17:08
Go to the top of the page
 
+Quote Post
Danis
сообщение Jan 31 2012, 17:33
Сообщение #6


Twilight Zone
***

Группа: Свой
Сообщений: 454
Регистрация: 17-02-09
Из: Челябинск
Пользователь №: 44 990



Цитата(Valentin-k @ Jan 31 2012, 21:04) *
считывает информацию из памяти с той же скорость что и записывает - это правильно, мне коллеги говорят что чтение должно быть намного быстрее записи...с учетом что пины настроены на 50МГЦ...


Не путайте время чтения с временем записи. Время чтения будет ограничено скорее максимальной частотой работы SPI контроллера или SPI flash памяти (если медленная). На запись страницы / стирание сектора, помимо времени загрузки (в случае записи страницы), потребуется дополнительное время (время стирания страницы(если доступно), сектора, блока, всего чипа ), не связанное с частотой SPI, это время оговорено в даташите на flash память.


Цитата(Valentin-k @ Jan 31 2012, 21:04) *
поэтому вопрос - возможно ли ускорить и вместо 400 мс на сектор, получить в районе 40-50 мс (при частоте 20МГЦ - по даташиту на флешку так написано)


Нет, меняйте память, если время не устраивает. Например, вот на эту: AT45DB161D with Two 528-Byte SRAM Buffer.

Цитата(Valentin-k @ Jan 31 2012, 21:04) *
и такой еще минивопросик - а обязательно при чтении постоянно слать Dummy byte, хотя без него чтение не происходит, но в том же даташите я не встречал чтобы писалось что перед каждым принимаемым байтом надо его отправлять...а в примерах - отправляют


Вам не помешает почитать по принципу работы SPI. Это не UART, тут нет Rx и Tx. Прием физически не отличается от передачи. На такт передачи одновременно идет и прием. Т.е. используется один регистр данных для передачи/приема, т.е. сдвиговый регистр.


--------------------
Magic Friend
Go to the top of the page
 
+Quote Post
DmitryM
сообщение Jan 31 2012, 18:36
Сообщение #7


Знающий
****

Группа: Свой
Сообщений: 583
Регистрация: 7-06-06
Из: Таганрог
Пользователь №: 17 840



Цитата(Valentin-k @ Jan 31 2012, 20:04) *
а обязательно при чтении постоянно слать Dummy byte, хотя без него чтение не происходит, но в том же даташите я не встречал чтобы писалось что перед каждым принимаемым байтом надо его отправлять...а в примерах - отправляют

А внимательно посмотреть datasheet??
Instruction Description One-byte instruction Address Dummy Data
code bytes bytes bytes
READ Read Data Bytes 0000 0011 03h 3 0 1 to ∞
FAST_READ Read Data Bytes at 0000 1011 0Bh 3 1 1 to ∞
Higher Speed

Ну и плюс выше озвученное про принцип работы SPI.
Go to the top of the page
 
+Quote Post
Valentin-k
сообщение Jan 31 2012, 19:02
Сообщение #8


Участник
*

Группа: Участник
Сообщений: 31
Регистрация: 27-01-12
Пользователь №: 69 923



спасибо за разъяснение
но маленькое уточнение, не совсем понял просто или не совсем ясно сформулировал свой вопрос:
Цитата(Danis @ Jan 31 2012, 20:33) *
Не путайте время чтения с временем записи. Время чтения будет ограничено скорее максимальной частотой работы SPI контроллера или SPI flash памяти (если медленная).


у меня в контроллере SPI подключен к шине APB1, у которой частота 36МГц, предделитель стоит 2, т.е. на SPI используется 18
время на запись всего сектора (256 страниц по 256 байт) занимает около 500мс по старому осциллографу точнее измерить не сумел, но с даташитом сходится - там написано что время записи одной страницы от 1,4 до 5 мс(от 359 мс до 1,28 с)
но время чтения получается таким же практически, ну может чуть меньше...хотя по логике при 18 МГц я должен читать за 30-40 мс (если частоту тактирования брать 18МГц)
единственное в начале грешил на слишком большое кол-во вызовов разных функция в цикле приема - ограничился написал по возможности одну функцию с прямым обращениям к регистру чтения и регистру флагов, но время не поменялось.. <-вот это верно?т.е. как бы само уточнение вот.
почему то кажется что ДМА тоже выигрыша не даст
я прав?

Цитата(DmitryM @ Jan 31 2012, 21:36) *
А внимательно посмотреть datasheet??
Instruction Description One-byte instruction Address Dummy Data
code bytes bytes bytes
READ Read Data Bytes 0000 0011 03h 3 0 1 to ∞
FAST_READ Read Data Bytes at 0000 1011 0Bh 3 1 1 to ∞
Higher Speed

Ну и плюс выше озвученное про принцип работы SPI.

ммм...я эту таблицу смотрел не раз, но там же указано что 3 байта адреса и 0 байт Dumme bytes или я не так ее трактую?
Go to the top of the page
 
+Quote Post
DmitryM
сообщение Feb 1 2012, 03:46
Сообщение #9


Знающий
****

Группа: Свой
Сообщений: 583
Регистрация: 7-06-06
Из: Таганрог
Пользователь №: 17 840



Цитата(Valentin-k @ Jan 31 2012, 22:02) *
ммм...я эту таблицу смотрел не раз, но там же указано что 3 байта адреса и 0 байт Dumme bytes или я не так ее трактую?

Вы же не привели какой командной Вы пользуетесь, для Read Dummy bytes не нужен, а для FAST READ нужен один в начале.
Go to the top of the page
 
+Quote Post
Danis
сообщение Feb 1 2012, 09:47
Сообщение #10


Twilight Zone
***

Группа: Свой
Сообщений: 454
Регистрация: 17-02-09
Из: Челябинск
Пользователь №: 44 990



Цитата(Valentin-k @ Jan 31 2012, 23:02) *
единственное в начале грешил на слишком большое кол-во вызовов разных функция в цикле приема - ограничился написал по возможности одну функцию с прямым обращениям к регистру чтения и регистру флагов, но время не поменялось.. <-вот это верно?т.е. как бы само уточнение вот.
почему то кажется что ДМА тоже выигрыша не даст
я прав?



Интересно, а как вы мерите время чтения/записи. Поясните. Тут смотреть нужно на конкретную микросхему SPI памяти. В общем, при записи, после завершения передачи последнего байта, нужно опрашивать (у внешней памяти) бит статус регистра, отвечающего за завершение операции (запись/стирание), когда он установиться/сброситься - это и будет означать завершение цикла записи, тогда уж с смотрите время. Со чтением все проще, никаких флагов опрашивать не надо. Передал upcode, адрес, может еще пару байт каких, в зависимости от микросхемы, дальше шлешь мусор любой, считывая регистр данных.
Вообще, если Вы на 18MHz шлете данные без применения DMA, у Вас паузы между посылками(байтами) будут и не маленькие, в сумме они дают не мало времени. Посмотрите это на осциллографе, сами убедитесь. Так, что DMA дает преимущества в плане скорости.


--------------------
Magic Friend
Go to the top of the page
 
+Quote Post
Valentin-k
сообщение Feb 1 2012, 10:28
Сообщение #11


Участник
*

Группа: Участник
Сообщений: 31
Регистрация: 27-01-12
Пользователь №: 69 923



осциллографом на шинах miso или mosi и clk.я через sw отладчик отдель запускаю цикл записи сектора,потом остановка и цикл чтения.
паузы при чтении вижу,наравне с размером страницы,даже чуть больше.а между самими байтами тоже.
я сейчас через дма начал делать,посмотрим что будет.
спасибо за наведение на путь и разъяснение))узнал кое-что.
Go to the top of the page
 
+Quote Post
Valentin-k
сообщение Feb 2 2012, 11:48
Сообщение #12


Участник
*

Группа: Участник
Сообщений: 31
Регистрация: 27-01-12
Пользователь №: 69 923



снова вопрос:а может флешка не успеть сохранить?
дело в том что запись через dma не происходит...на осциллографе вижу всю посылку,а считываю ff
в тоже время если просто через spi пишу,а считываю через dma-все нормально...
Go to the top of the page
 
+Quote Post
Valentin-k
сообщение Feb 2 2012, 15:03
Сообщение #13


Участник
*

Группа: Участник
Сообщений: 31
Регистрация: 27-01-12
Пользователь №: 69 923



задам вопрос по другому!
вот написан модуль у меня общения с DMA (инициализацию не привожу)
CODE
{
for(int k=0;k<255;k++)
{ data[k]=k;
buffSPI_Tx[k]=k;
buffSPI_Rx[k]=0;
buff[k]=0;
}
init_DMA_SPI();

//начало записи
buffSPI_Tx[0]=WREN;
buffSPI_Tx[1]=WRITE;
buffSPI_Tx[2]=0x00;
buffSPI_Tx[3]=0x00;
buffSPI_Tx[4]=0x00;


SPI_FLASH_CS_LOW();
TX_DMA_SPI();

SPI_FLASH_CS_HIGH();
//конец записи
//начало чтения
buffSPI_Tx[0]=READ;
buffSPI_Tx[1]=0x00;
buffSPI_Tx[2]=0x00;
buffSPI_Tx[3]=0x00;

DMA2_Channel1->CNDTR = 256;
DMA2_Channel2->CNDTR = 256;
SPI_FLASH_CS_LOW();
TX_DMA_SPI();
SPI_FLASH_CS_HIGH();
//конец чтения

buffSPI_Rx[3]=0x00; //контрольный
buff[0]=0; //

}


а теперь функция:

void TX_DMA_SPI(void)
{


DMA_Cmd(DMA2_Channel2,ENABLE);
DMA_Cmd(DMA2_Channel1,ENABLE);
while(!DMA_GetFlagStatus(DMA2_FLAG_TC2));

DMA_ClearITPendingBit(DMA2_IT_TC2);
//DMA_ClearITPendingBit(DMA2_IT_TC1|DMA2_IT_GL1|DMA2_IT_HT1);

DMA_Cmd(DMA2_Channel2,DISABLE);
DMA_Cmd(DMA2_Channel1,DISABLE);

}




дело все в том что в таком виде в память ничего не пишется...читаю только 0xFF...
а если вместо функции записи через ДМА я ставлю просто функцию записи через SPI, а читаю через DMA - все работает

Сообщение отредактировал IgorKossak - Feb 2 2012, 15:10
Причина редактирования: [codebox]!!!
Go to the top of the page
 
+Quote Post
011119xx
сообщение Feb 3 2012, 04:55
Сообщение #14


Местный
***

Группа: Свой
Сообщений: 381
Регистрация: 5-07-05
Из: Уфа
Пользователь №: 6 544



Рекомендую проверить состояние битов защиты секторов от записи. Если как вы говорите запись происходит очень быстро, то она просто не происходит по причине защиты от записи. Перед записью новых данных, старые все же надо сначала стирать, иначе потом при чтении получите данные отличные от записываемых.
Go to the top of the page
 
+Quote Post
Valentin-k
сообщение Feb 3 2012, 05:12
Сообщение #15


Участник
*

Группа: Участник
Сообщений: 31
Регистрация: 27-01-12
Пользователь №: 69 923



Цитата(011119xx @ Feb 3 2012, 08:55) *
Рекомендую проверить состояние битов защиты секторов от записи. Если как вы говорите запись происходит очень быстро, то она просто не происходит по причине защиты от записи. Перед записью новых данных, старые все же надо сначала стирать, иначе потом при чтении получите данные отличные от записываемых.


я провожу очистку сектора.но тут дело даже не в защитных битах-запись просто через spi проходит нормально,и чтение этой записи через dma успешное,массивы совпадают,а вот запись через dma-нет...
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th June 2025 - 15:27
Рейтинг@Mail.ru


Страница сгенерированна за 0.01525 секунд с 7
ELECTRONIX ©2004-2016