Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32 конец клока SPI
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
RadiatoR
Всем доброго дня.
Завожу MRF24J40. SPI.
Аппаратного CS нету, вылезаем софтверно.

Ногу CS опускаю в начале записи, поднимаю по прерыванию RXNEIE. Все вроде бы нормально (процесс записи в регистр 0x18 значения 0x98):

Но есть проблема - как оказалось запись в чип происходит по спаду клока, пока еще выбран CS. Точнее захват может и по фронту происходит, но запись точно по спаду. И тут возникает проблема - прерывание происходит на половине последнего клока - то есть его фронт уже был, прошла четверть периода клока и прерывается. Соответственно я поднимаю CS. Но как показали опыты если его поднять до того, как клок упадет вниз запись не произведется.

Собственно вопрос - как оптимально сдвинуть CS на половину периода клока? То есть после того, как он опустится.

Спасибо.

PS
Очень интересно - проблема решилась сама собой с увеличением частоты. На скриншоте частота = 24МГц/256. поставил делитель 64 и CS сдвинулся более чем на пол периода

ViKo
Поднимайте ногу CS по SPI_SR_BSY.
AlanDrakes
Лично у меня - вот такая конструкция:
Код
    GPIOA->BSRR = (GPIO_BSRR_BR_2 | GPIO_BSRR_BR_6);    // nCS DN, D/C# DN
    SPI1->DR = command;
    while (!(SPI1->SR & SPI_SR_TXE));
    while (SPI1->SR & SPI_SR_BSY);
    GPIOA->BSRR = GPIO_BSRR_BS_2;        // nCS UP


Магия? Возможно. Но без первой инструкции ожидания порой пролетал мимо передачи и пин /CS дёргался вниз-вверх за 2 такта, а уже после этого начиналась передача. Третью строку можно убрать, но на свой страх и риск.
scifi
Цитата(RadiatoR @ Sep 17 2016, 16:05) *
Очень интересно - проблема решилась сама собой с увеличением частоты. На скриншоте частота = 24МГц/256. поставил делитель 64 и CS сдвинулся более чем на пол периода

Ничего интересного. Просто обработчик прерывания не успел дёрнуть CS раньше. Сегодня не успел, а завтра успеет. Следовательно, не вариант.
RadiatoR
2ViKo не вариант - не использую вайлы

2scifi при частоте 375к у ядра на периода клока 128 тактов. Вполне возможно, что задержался. Но это был его самый "быстрый путь" по коду. так что врядли будет быстрее.

А вот mrf так и не завелась толком... Отправляет вроде, прерывание на отправку генерит, в статусе все ок. А вот приемник пару раз с антенной на прерывание входил и все. Никак не заработает. И мощности добавил и антенну поменял.. Не понятно что не так
jcxz
Цитата(RadiatoR @ Sep 17 2016, 19:05) *
Собственно вопрос - как оптимально сдвинуть CS на половину периода клока? То есть после того, как он опустится.

Использовать другой режим SPI (биты CPOL, CPHA).
ViKo
Цитата(RadiatoR @ Sep 17 2016, 21:29) *
2ViKo не вариант - не использую вайлы

В прерывании от TXE (или от RXNE, если очень хочется) дождитесь BSY, не много потеряете. Если внимательно рассмотрите RM, увидите на картинках, что да как.
RadiatoR
Цитата(jcxz @ Sep 18 2016, 07:41) *
Использовать другой режим SPI (биты CPOL, CPHA).


Это не то. Они не дали того эффекта

Цитата(ViKo @ Sep 18 2016, 08:59) *
В прерывании от TXE (или от RXNE, если очень хочется) дождитесь BSY, не много потеряете. Если внимательно рассмотрите RM, увидите на картинках, что да как.

Ждать тоже не хочется - все таки это не хороший тон ждать в прерывании. В любом случае я добился своего.
А по поводу mrf - походу антенна не заходит в кабель. Кабель и антенну купил в разных местах и промазал походу.
вот такой набор:


Ее подергаешь бац - несколько пакетов подряд примет, потом о5 пропадает. Короче антенну заменю.
scifi
Цитата(RadiatoR @ Sep 18 2016, 11:20) *
Ждать тоже не хочется - все таки это не хороший тон ждать в прерывании.

Глупости.
Нехороший тон - это делать то, чего не понимаешь.
Если же понимание присутствует, то можно и ждать в прерывании, и рвать шаблоны слабонервным ещё тысячью способов, одновременно указывая любителям хорошего тона, куда им можно пойти.
ViKo
Цитата(RadiatoR @ Sep 18 2016, 11:20) *
Ждать тоже не хочется - все таки это не хороший тон ждать в прерывании. В любом случае я добился своего.

Да, увеличив скорость, добились. А когда уменьшите, косяк вылезет назад. Если будете проверять BSY, то вам и ждать не придется на высокой скорости, он уже выключится. А на низкой спасет.
RadiatoR
Цитата(ViKo @ Sep 18 2016, 12:23) *
Да, увеличив скорость, добились. А когда уменьшите, косяк вылезет назад. Если будете проверять BSY, то вам и ждать не придется на высокой скорости, он уже выключится. А на низкой спасет.

Уменьшать и не планирую - низкую ставил пока отлаживал. Вообще попробую с BSY. Если на осцилле будет такая же картина может и оставлю.
scifi
Вообще, конечно, плохо, что нет у STM32 нужного прерывания. Похожая история с I2C: непрерывный обмен только на прерываниях без ожидания флагов часто сделать невозможно.
Если хочется совсем по феншую, можно привлечь таймер для доп. задержки. Но, боюсь, в данном случае это не даст никакого выигрыша по сравнению с простым и недолгим ожиданием флага BUSY.
RadiatoR
В общем я гляну как будет себя вести ожидание BSY и сколько тактов оно на себя сожрет и посмотрю

Вообще у стм порой странности бывают. Например с той же ножкой NSS. Она, конечно, нужна не для Chip select, но могли же добавить в нее такую возможность... В конце концов очень часто бывает, что на 1 SPI вешают только 1 девайс, а тут такая засада...
jcxz
Цитата(RadiatoR @ Sep 18 2016, 14:20) *
Это не то. Они не дали того эффекта

Что именно "не то"?
Судя по картинке у Вас CPOL=0, CPHA=0. Т.е. - Вы настроили защёлкивание данных по фронту SCLK. И в то же время пишете:
Цитата(RadiatoR @ Sep 17 2016, 19:05) *
как оказалось запись в чип происходит по спаду клока,

Так всё-таки: чип MRF24J40 защёлкивает данные по фронту или по спаду??? Неужели на этот чип нет доки? Или читать не умеете?
Если всё-таки по спаду, то CPOL=1, CPHA=0 - должно решить проблему.
RadiatoR
Цитата(jcxz @ Sep 18 2016, 17:01) *
Или читать не умеете?


К вашему сведению не всем людям нравится читать такие "наезды". Прошу в отношении меня впредь от них воздержаться.

А по сабжу - как происходит запись/захват я описал еще в первом посте. Захват происходит по фронту. Все как полагается. Но, видимо, захват значения (при записи в регистры mrf) происходит по фронту, а запись этого значения по спаду, при включенном CS. Опыты показали именно такое поведение.
CPOL и CPHA созданы для другого.
scifi
Цитата(RadiatoR @ Sep 19 2016, 13:08) *
CPOL и CPHA созданы для другого.

Топор создан для того, чтобы рубить, но это не значит, что им невозможно забить гвоздь.
Так что "создан для другого" - это аргумент приблизительно такого же качества, как и ссылки на "хороший тон" biggrin.gif
Короче, если без иносказаний, то просто попробуйте. Результаты легко могут вас удивить.
RadiatoR
Прочтите внимательнее мое сообщение:
Цитата(RadiatoR @ Sep 18 2016, 11:20) *
Они не дали того эффекта


Писал я в прошлом времени - значит попробовал. Перестало вообще работать.
scifi
"Не верю" (С)
jcxz
Цитата(RadiatoR @ Sep 19 2016, 16:08) *
А по сабжу - как происходит запись/захват я описал еще в первом посте. Захват происходит по фронту.

Т.е. - это не Вы писали, а Ваш клон наверное?:
Цитата(RadiatoR @ Sep 17 2016, 19:05) *
Но есть проблема - как оказалось запись в чип происходит по спаду клока, пока еще выбран CS. Точнее захват может и по фронту происходит, но запись точно по спаду.

И что такое в Вашей терминологии "запись" и "захват"? И в чём между ними разница? Думаю многим тут будет интересно.

Цитата(RadiatoR @ Sep 19 2016, 16:08) *
Все как полагается. Но, видимо, захват значения (при записи в регистры mrf) происходит по фронту, а запись этого значения по спаду, при включенном CS. Опыты показали именно такое поведение.

Что есть "запись", а что есть "захват"?
Ещё раз настоятельно советую наконец-то открыть мануал на чип, а не заниматься "опытами".

Цитата(RadiatoR @ Sep 19 2016, 16:08) *
CPOL и CPHA созданы для другого.

Интересно - для чего же? Просветите. wink.gif
RadiatoR
Что бы лишний раз не распинаться опишу - формат работы с mrf стандартный. Работает нормально при CPOL и CHPA = 0. Мне тоже интересно почему чип отказывается производить запись по фронту.
В самом первом посте в 1 скрине я пытаюсь записать байт в регистр. Он не записывается если CS поднимается до спада клока. Если точно таким же образом прочитать данные - они выведутся по фронту клока. То есть так как и полагается. Получается либо запись (она же захват (может буфер какой внутри есть.. я не знаю)) осуществляется по спаду и чтение по фронту, либо есть какой-то буфер захвата.

CPOL и CHPA меняют режимы. Не будем придираться
scifi
Цитата(RadiatoR @ Sep 19 2016, 16:11) *
В самом первом посте в 1 скрине я пытаюсь записать байт в регистр. Он не записывается если CS поднимается до спада клока.

Специально заглянул в даташит. Там на картинке видно, что SCK должен упасть в 0 перед подъёмом CS. Так что нарушаете. Цифры времянки не приведены (видимо, планируют позже дописать), но мне известны микросхемы, у которых то же самое, и там времянка не оставляет сомнений, что SCK должен упасть перед тем, как CS поднимется.
Опять же из даташита видно, что есть единственный правильный режим CPOL = 0, CHPA = 0, так что менять его не получится.
Obam
Цитата(RadiatoR @ Sep 19 2016, 17:11) *
… Работает нормально при CPOL и CHPA = 0. Мне тоже интересно почему чип отказывается производить запись по фронту.
В самом первом посте в 1 скрине я пытаюсь записать байт в регистр. Он не записывается если CS поднимается до спада клока…

Только так он и будет работать (CPOL = 0: SCK to 0 when idle, CHPA = 0: The first clock transition is the first data capture edge) см. рис. 2-4, 2-5 стр. 12 DS39776C.

В даташите на этот трансивер английским по белому:"The CS pin must be held low while communicating with the MRF24J40." Ну и опять же рисунок недвусмысленно это подтверждает.

CS не должен (не может, если не хотим чудес) сниматься (0 --> 1) раньше заднего фронта (1 --> 0) последнего импульса SCK.

Хоть и опередили, но CS ↑ after SCK Edge не менее 50нс.
RadiatoR
Вот вот. Я и говорю об этом. Всмысле про то, что если поднять CS раньше, то он не запишется. График я видел. Просто чтение нормально проходит если CS бросить раньше, а запись нет. Вот и встал вопрос об продлении CS сигнала без ожидания.

В общем что бы не разглагольствовать предлагаю закончить. Результата я добился.
Всем спасибо за помощь.
jcxz
Простой способ продлить CS дольше не прибегая к таймеру и ожиданиям: в последнем прерывании RXNEIE уменьшить длину слова до минимума и выплюнуть на передачу ещё одно слово. Если логика внутри чипа сделана прямыми руками, то это никак не повредит обмену, так как по подъёму CS битовый счётчик будет сброшен. Хотя на этот счёт лучше всё-таки уточнить по доке.
Шаманъ
Цитата(jcxz @ Sep 19 2016, 21:03) *
Простой способ продлить CS дольше не прибегая к таймеру и ожиданиям

У меня проще - обмен идет с использованием DMA, CS управляется в прерывании от DMA контроллера, по окончании приема блока данных. К этому времени уже все передано и принято.
RadiatoR
Цитата(Шаманъ @ Sep 20 2016, 15:23) *
У меня проще - обмен идет с использованием DMA, CS управляется в прерывании от DMA контроллера, по окончании приема блока данных. К этому времени уже все передано и принято.


Через DMA я скорее всего делать не буду, но попробовать можно. Хотя бы посмотреть как себя будет CS вести.
Alechek
Цитата(RadiatoR @ Sep 20 2016, 21:58) *
Через DMA я скорее всего делать не буду, но попробовать можно.

Ну и зря. Особенно, если устройство с батарейным питанием. С DMA обмен будет проходить быстрее, а следовательно, экономим немного Джоулей на работе ядра.
RadiatoR
Цитата(Alechek @ Sep 21 2016, 07:30) *
Ну и зря. Особенно, если устройство с батарейным питанием. С DMA обмен будет проходить быстрее, а следовательно, экономим немного Джоулей на работе ядра.


Не, батарейки нет никакой. Да и быстродействие особое не нужно (по крайней мере на прерываниях скорости более чем достаточно, а поднять DMA это 1-2 дня будет - для меня это дорого выйдет)
Alechek
Стандартные библиотеки не наш метод? Уважуха! beer.gif
По использованию без библиотек для начала все можно глянуть сюда
http://we.easyelectronics.ru/STM32/primery...-bibliotek.html

А так все просто:

Для STM32F10x
Код
void DmaXfer(void const * txbuf,
             void       * rxbuf,
             int len)
{
  DMA1_Channel2->CCR = 0;
  DMA1_Channel3->CCR = 0;
  
  DMA1->IFCR = DMA_IFCR_CGIF2;
  
  DMA1_Channel2->CPAR = (uint32_t)&SPI1->DR; //DR Base
  DMA1_Channel2->CMAR = (uint32_t)rxbuf;
  DMA1_Channel2->CNDTR = len;
  
  DMA1_Channel3->CPAR = (uint32_t)&SPI1->DR; //DR Base
  DMA1_Channel3->CMAR = (uint32_t)txbuf;
  DMA1_Channel3->CNDTR = len;
  
  DMA1_Channel2->CCR = 0
                      | DMA_CCR_MSIZE_0
                      | DMA_CCR_PSIZE_0 // 16 bit
                      | DMA_CCR_MINC
                      | DMA_CCR_TCIE
                      | DMA_CCR_EN;
                        
  DMA1_Channel3->CCR = 0
                      | DMA_CCR_MSIZE_0
                      | DMA_CCR_PSIZE_0 // 16 bit
                      | DMA_CCR_MINC
                      | DMA_CCR_DIR
                      | DMA_CCR_EN;

  SPI1->CR2 |= 0
   |SPI_CR2_RXDMAEN // разрешить передачу принятых данных через DMA
   | SPI_CR2_TXDMAEN; // Разрешить принимать данные для передачи через DMA  
   ;  
  
  while (!(DMA1->ISR & (DMA_ISR_TCIF2 | 0)));
  
  return;
}
RadiatoR
Приятно видеть людей, которые понимают в чем прелесть собственного кода без сторонних либ и ХАЛов. Спасибо.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.