011119xx
May 11 2011, 08:03
Собственно говоря, что хочется понятно из названия темы. Уточню лишь, что хочу использовать 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));
... а что дальше?
akimych
May 11 2011, 21:45
В примере 2 SPI используюются, т.к. они гоняют байты из одного SPI в другой. А иначе ест-но только один канал нужен - мастер. Слейвом будет M25P64.
Инициализация уже есть (до /* Enable DMA channels */).
Передача - настраиваем дма (адрес, длина буфера, при выключеном канале) и в ключаем канал. Ждем окончания передачи.
С приемом тоже настраиваем, а потом возможно 2 варианта. Т.к. для приема нужно выдать клок, то либо надо в цикле (или тоже через дма) отправлять что-нибудь, либо включить режим полудуплекс-прием, когда SPI сам будет непрерывно гнать клок, пока его не выключат.
Я использовал второй способ, в частности из-за того, что есть режим позволяющий сэкономить один вывод. Но столкнулся с такой особенностью, что при SPI_BaudRatePrescaler_2 и SPI_DataSize_8b иногда теряются байты. Объяснение у меня этому только одно - DMA не успевает вычитывать данные из SPI. Правда у меня еще АЦП через дма работает.
ISK2010
May 13 2011, 04:13
А я делаю так:
1) В фоне отправляю команду флэшке, а пока идет отправка настраиваю DMA на нужный буфер и количество байт.
2) После передачи последнего байта команды включаю DMATXE
3) После приема последнего байта ответа на команду включаю DMARXE
В обработчике прерывания по приему последнего байта DMA TC устанавливаю нужный флажок и произвожу "девыбор" флэшки
011119xx
May 13 2011, 05:37
А на код можно посмотреть?
Valentin-k
Jan 31 2012, 17:04
а можно вопрос по теме!я вообще с флешками до этого не работал, а тут подключил к STM32 m25p64
все работает, записывает, читает...время записи совпадает с указанным в даташите...
но вот считывает информацию из памяти с той же скорость что и записывает - это правильно, мне коллеги говорят что чтение должно быть намного быстрее записи...с учетом что пины настроены на 50МГЦ...
ДМА не пробовал.
поэтому вопрос - возможно ли ускорить и вместо 400 мс на сектор, получить в районе 40-50 мс (при частоте 20МГЦ - по даташиту на флешку так написано)
и такой еще минивопросик - а обязательно при чтении постоянно слать Dummy byte, хотя без него чтение не происходит, но в том же даташите я не встречал чтобы писалось что перед каждым принимаемым байтом надо его отправлять...а в примерах - отправляют
Цитата(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. Прием физически не отличается от передачи. На такт передачи одновременно идет и прием. Т.е. используется один регистр данных для передачи/приема, т.е. сдвиговый регистр.
DmitryM
Jan 31 2012, 18:36
Цитата(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.
Valentin-k
Jan 31 2012, 19:02
спасибо за разъяснение
но маленькое уточнение, не совсем понял просто или не совсем ясно сформулировал свой вопрос:
Цитата(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 или я не так ее трактую?
DmitryM
Feb 1 2012, 03:46
Цитата(Valentin-k @ Jan 31 2012, 22:02)

ммм...я эту таблицу смотрел не раз, но там же указано что 3 байта адреса и 0 байт Dumme bytes или я не так ее трактую?
Вы же не привели какой командной Вы пользуетесь, для Read Dummy bytes не нужен, а для FAST READ нужен один в начале.
Цитата(Valentin-k @ Jan 31 2012, 23:02)

единственное в начале грешил на слишком большое кол-во вызовов разных функция в цикле приема - ограничился написал по возможности одну функцию с прямым обращениям к регистру чтения и регистру флагов, но время не поменялось.. <-вот это верно?т.е. как бы само уточнение вот.
почему то кажется что ДМА тоже выигрыша не даст
я прав?
Интересно, а как вы мерите время чтения/записи. Поясните. Тут смотреть нужно на конкретную микросхему SPI памяти. В общем, при записи, после завершения передачи последнего байта, нужно опрашивать (у внешней памяти) бит статус регистра, отвечающего за завершение операции (запись/стирание), когда он установиться/сброситься - это и будет означать завершение цикла записи, тогда уж с смотрите время. Со чтением все проще, никаких флагов опрашивать не надо. Передал upcode, адрес, может еще пару байт каких, в зависимости от микросхемы, дальше шлешь мусор любой, считывая регистр данных.
Вообще, если Вы на 18MHz шлете данные без применения DMA, у Вас паузы между посылками(байтами) будут и не маленькие, в сумме они дают не мало времени. Посмотрите это на осциллографе, сами убедитесь. Так, что DMA дает преимущества в плане скорости.
Valentin-k
Feb 1 2012, 10:28
осциллографом на шинах miso или mosi и clk.я через sw отладчик отдель запускаю цикл записи сектора,потом остановка и цикл чтения.
паузы при чтении вижу,наравне с размером страницы,даже чуть больше.а между самими байтами тоже.
я сейчас через дма начал делать,посмотрим что будет.
спасибо за наведение на путь и разъяснение))узнал кое-что.
Valentin-k
Feb 2 2012, 11:48
снова вопрос:а может флешка не успеть сохранить?
дело в том что запись через dma не происходит...на осциллографе вижу всю посылку,а считываю ff
в тоже время если просто через spi пишу,а считываю через dma-все нормально...
Valentin-k
Feb 2 2012, 15:03
задам вопрос по другому!
вот написан модуль у меня общения с 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 - все работает
011119xx
Feb 3 2012, 04:55
Рекомендую проверить состояние битов защиты секторов от записи. Если как вы говорите запись происходит очень быстро, то она просто не происходит по причине защиты от записи. Перед записью новых данных, старые все же надо сначала стирать, иначе потом при чтении получите данные отличные от записываемых.
Valentin-k
Feb 3 2012, 05:12
Цитата(011119xx @ Feb 3 2012, 08:55)

Рекомендую проверить состояние битов защиты секторов от записи. Если как вы говорите запись происходит очень быстро, то она просто не происходит по причине защиты от записи. Перед записью новых данных, старые все же надо сначала стирать, иначе потом при чтении получите данные отличные от записываемых.
я провожу очистку сектора.но тут дело даже не в защитных битах-запись просто через spi проходит нормально,и чтение этой записи через dma успешное,массивы совпадают,а вот запись через dma-нет...
Genadi Zawidowski
Feb 3 2012, 05:33
Цитата(Valentin-k @ Feb 3 2012, 09:12)

я провожу очистку сектора.но тут дело даже не в защитных битах-запись просто через spi проходит нормально,и чтение этой записи через dma успешное,массивы совпадают,а вот запись через dma-нет...
При чтении по DMA обеспечиваете выдачу 0xff по SPI? Я программировал вывод процессора на выдачу 1 в таком случае.
Valentin-k
Feb 3 2012, 05:41
я нули шлю,при чтении нужно тактирование делать,нулями и делаю. массив buffSPI_Tx у меня нулевой,только в его нулевой элемент записываю команду на чтение READ,а три следующие адрес,в данном случае нулевой.далее указываю буффер приема и передачи и включаю два канала...
по завершению передачи в buffSPI_Rx я имею страницу считанную из флеша(за исключением последних 4 байт,но это мелочь,буффер увеличить на 4 и всю страницу получу или както по другому-это не важно)-это все работает!проблема с записью...чую где то глупый косяк,да опыта мало еще с 32-х разрядными
DmitryM
Feb 3 2012, 08:44
Цитата(Valentin-k @ Feb 3 2012, 08:41)

проблема с записью...чую где то глупый косяк,да опыта мало еще с 32-х разрядными
Ну вот, оказывается таки проблема с записью. А Вы учитываете что перед каждой записью нужно дать команду WREN и контроллировать WEL?
The Write Enable Latch (WEL) bit must be set prior to every Page Program (PP), Sector Erase (SE), Bulk Erase (BE) and Write Status Register (WRSR) instruction.
Valentin-k
Feb 3 2012, 08:49
про команду я знаю и сейчас уже локализовался - по dma эта команда не идет...не ставится бит...и не могу понять почему.в даташите про времена ничего не сказано,а подаю ее так же как и просто через spi писал.
по обычным функциям стандартной библиотеки spi все пишется
011119xx
Feb 6 2012, 05:03
А канал DMA перестраивается или нет при попытке установить этот бит ?
Valentin-k
Feb 6 2012, 20:22
в каком смысле перестраивается?
я с битом разобрался, он стал ставится когда я отдельно начал слать команду на разрешение записи:
buffSPI_Tx[0]=WREN;
SPI_FLASH_CS_LOW();
TX_DMA_SPI();
SPI_FLASH_CS_HIGH();
а тут уже запрос на регистр статуса
аналогично
buffSPI_Tx[0]=код команды запроса;
DMA2_Channel1->CNDTR = 3;
DMA2_Channel2->CNDTR = 3;
SPI_FLASH_CS_LOW();
TX_DMA_SPI();
SPI_FLASH_CS_HIGH();
и в ответ получаю заветную 0х02 - как раз 1-ка в том бите
но потом:
buffSPI_Tx[0]=WRITE;
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();
и записи нет((((
на осциллографе всю передачу вижу
Valentin-k
Feb 7 2012, 07:34
а может дело в флагах которые ставит дма,а я не сбрасываю?
smalcom
Feb 25 2012, 08:17
Плохо смотрю или Valentin-k действительно не проверяет WriteInProgress бит?
Для просмотра полной версии этой страницы, пожалуйста,
пройдите по ссылке.