Перейти к содержанию
    

Запись регистров разной длины по SPI с DMA

Добрый день, изучая AD9859 решил сделать инициализацию в виде все настроенные значения занести в один массив и его с помощью DMA перегнать а AD9859, но возникла проблема, как дергать CS ? его надо надо переключать то через 5 байт то через 3 байта.

 

  // ASF
  AD9859_CS_LOW
  Write_DDS(0x02);   // ADDRESS
  Write_DDS(0x00);   // DEFAULT
  Write_DDS(0x00);
  AD9859_CS_HIGH
  AD9859_UPDATE_HIGH
  delay_us(1);
  AD9859_UPDATE_LOW


  // CFR1
  AD9859_CS_LOW
  Write_DDS(0x00);   // ADDRESS
  Write_DDS(0x00);   // DEFAULT
  Write_DDS(0x00);
  Write_DDS(0x00);
  Write_DDS(0x00);
  AD9859_CS_HIGH
  AD9859_UPDATE_HIGH
  delay_us(1);
  AD9859_UPDATE_LOW

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

но возникла проблема, как дергать CS ?
Инициализацию разбить на команды, на каждую команду запускать DMA, перед запуском DMA и в прерывании окончания персылки дергать CS.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Добрый день, изучая AD9859 решил сделать инициализацию в виде все настроенные значения занести в один массив и его с помощью DMA перегнать а AD9859, но возникла проблема, как дергать CS ? его надо надо переключать то через 5 байт то через 3 байта.

В некоторых МК имеются полнофункциональные SPI-интерфейсы, в которых есть управления линиями CS в слове передаваемых данных к примеру. Например Infenion такое умеет. Также в Тексасовских МК такое есть (Tiva, OMAP L-13x). Так что, если есть возможность - возьмите такой МК.

В других МК, имеющих полнофункциональные DMA-контроллеры, такое можно сделать заведя события запуска DMA не от SPI, а от какого либо таймера. Запрограммировав DMA в режиме передачи "свЯзных списков", можно разными пересылаемыми DMA-блоками внутри одного списка, управлять и линиями CS (через GPIO например) и загружать в SPI данные. Я реализовывал такой метод на LPC17xx. Многие другие МК также имеют DMA с функционалом "свЯзных списков"

В STM32 с его бедной периферией, нет ни того ни другого. Выбирать его для каких-то серьёзных операций с периферией - глупо. Сомневаюсь что на нём можно как-то реализовать это аппаратно.

Так что если ещё не поздно - поменяйте на что-то другое, где есть более мощная периферия.

 

Инициализацию разбить на команды, на каждую команду запускать DMA, перед запуском DMA и в прерывании окончания персылки дергать CS.

Вопрос-то был как раз в том - "как не разбивать?"

 

PS: На STM32 можно извратиться - сэмулировать недостающий в его DMA режим свЯзных списков (с помощью доп. канала DMA и таймера). Тогда да - получится без задействования CPU передать весь массив, дёргая внутри него CS-ом в нужных местах. Но такая реализация получается очень громоздкой B)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вопрос-то был как раз в том - "как не разбивать?"
Я вопрос понял иначе - "как прикрутить DMA вместо отсылки каждого байта вручную, но при этом дергать CS".

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я вопрос понял иначе - "как прикрутить DMA вместо отсылки каждого байта вручную, но при этом дергать CS".

Как я понял - ТС хочет один раз запустить некий процесс при помощи CPU и только в конце его получить одно прерывание завершения.

ТС нас рассудит как появится ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да jcxz прав хочу все скопищем что бы отправлялось, хотя в данном случае это не сильно принципиально, но просто было интересно узнать как такое можно сделать, хотя бы на данном примере.

В некоторых МК имеются полнофункциональные SPI-интерфейсы, в которых есть управления линиями CS в слове передаваемых данных к примеру.

Это типа в данных дополнительным битом указываешь когда CS переключить? У STM есть вывод CS(NSS) но он там переключается через каждый байт, по этому не когда не использовал его.

такое можно сделать заведя события запуска DMA не от SPI, а от какого либо таймера

Такое есть в STM планирую сделать для записи частоты (там будет фиксированная длинна и от сигнала CS можно будет запускать передачу)

 

Можно подробнее про режим связанных списков ? в Stm32f446 есть режим Double buffer mode это не то ? я еще с ним толком не разобрался. по этому и спрашиваю

 

Кстати есть МК с режимом DMA периферия-> периферия это типа когда из пзу передаешь контент.

 

Так что если ещё не поздно - поменяйте на что-то другое, где есть более мощная периферия.

Уже поздно так что буду извращаться "с помощью доп. канала DMA и таймера" заодно и разберусь с dma досконально.

Изменено пользователем pokk

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Добрый день, изучая AD9859 решил сделать инициализацию в виде все настроенные значения занести в один массив и его с помощью DMA перегнать а AD9859, но возникла проблема, как дергать CS ? его надо надо переключать то через 5 байт то через 3 байта.

Если AD9859 понимает незначащие нули, то можно выровнять нулями в начале блоки данных на 5 и запустить таймер с периодом передачи блоков. А у таймера на одном из каналов формировать ШИМом CS.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это типа в данных дополнительным битом указываешь когда CS переключить? У STM есть вывод CS(NSS) но он там переключается через каждый байт, по этому не когда не использовал его.

Можно подробнее про режим связанных списков ? в Stm32f446 есть режим Double buffer mode это не то ? я еще с ним толком не разобрался. по этому и спрашиваю

В DMA STM32 нет режима связных списков - это самый главный минус его DMA. Так как режим "свЯзных списков" имеет самые большие возможности из всех других режимов DMA. Можно даже сказать, что все другие режимы - это частные случаи режима связных списков. Имея только этот режим, все остальные режимы DMA (и двойной буфер и циклический и пр.) можно реализовать через связные списки.

Режим "связных списков" - это когда указываешь DMA не один блок для пересылки, а цепочку (произвольной длины) таких блоков, у каждого блока - свой размер, свои адреса целевой/источник и своё слово управления. Таким списком можно например управлять сразу разной периферией в одной пересылке (например GPIO и SPI).

 

А в Вашем случае можно попытаться реализовать какое-то подобие этого режима на STM32 из говна и палок на нескольких таймерах + неск. каналов DMA.

Ключевое тут то, что у Вас SPI-мастер и не очень важна времянка. NSS тут не при чём. CS управлять через GPIO. Общий алгоритм такой же, как в связных списках. Но реализовывать придётся через известное место.

И почитайте немного как работает DMA, узнайте что такое целевой адрес периферии при пересылке и что такое запрос от периферии и чем они отличаются.

Так вот - запросы на пересылки надо брать от таймера, а не SPI.

Блок-схема:

Таймер с определённым периодом дёргает 1-й DMA канал, который на каждое такое событие выполняет пересылку в регистры управления 2-го DMA-канала - программирует его для очередной передачи.

Каждый такой блок программирует 2-й DMA канал на очередную пересылку.

1-я пересылка блока конфигурации - в регистры GPIO, чтобы установить CS=0.

2-я пересылка блока конфигурации в регистры управления 3-го DMA-канала, которая запрограммирует его на обслуживание SPI (только передача) и пересылку в SPI (по его запросам) очередного блока данных.

3-я пересылка блока конфигурации - в регистры GPIO, чтобы установить CS=1.

И так далее через интервалы времени, определяемые таймером.

Синхронизация 1-го DMA - от событий таймера; второй DMA - без синхры, режим память-память; 3-й DMA - синхра от SPI.

Как-то примерно так. Это примерная схема. Подробно - уже сами, изучив как следует матчасть (SPI, таймеры, DMA, их взаимосвязи).

 

PS: Да - в терминологии юзермануала STM32 следует читать "каналы DMA" как "потоки DMA". А "запросы DMA" как "каналы DMA" ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

jcxz, Благодарю за ответ, что-то даже и в мыслях не было что можно DMA настраивать периферию, теперь возможности гораздо расширились.

Пока еще не совсем въехал в алгоритм, конкретно буду в понедельник с разбираться. Таким образом можно передавать и считывать блоками по SPI N- количество байт от 1-65535? Просто есть другая задача не думал что этот вопрос затронет её там мне как раз надо передать данные в размере от 1-65535 байт, потом щелкнуть CS что данные закончились и дальше надо передать 1-2 байта команды что бы данные уже отправились. Пока приходилось решать это программным путем но, это оказался дикий геморрой, если получиться данный алгоритм применить и туда это будет круто, ещё раз спасибо за идею =)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Пока еще не совсем въехал в алгоритм, конкретно буду в понедельник с разбираться. Таким образом можно передавать и считывать блоками по SPI N- количество байт от 1-65535?

Конечно можно. У Вас же SPI-мастер. И если тактирование его идёт от того-же источника (это важно!), что и таймер, то можно по таймеру определять когда регистр передачи SPI.DR опустошается (с небольшим запасом брать) и можно писать новые данные в него. И флаги статуса SPI можно не смотреть. А соответственно и GPIO тоже управлять по этой же временной диаграмме.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Разбираюсь с алгоритмом, пока понял что таймером мы генерируем сигналы CS а потом между ними вставляет передачу SPI так ?

Пока не могу понять, 1-я пересылка блока конфигурации, вторая и третья посылка закидываются от каждого события таймера? Или все скопищем?

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Разбираюсь с алгоритмом, пока понял что таймером мы генерируем сигналы CS а потом между ними вставляет передачу SPI так ?

Нет, не так. Я же вроде подробно разжевал в сообщении N8...

Таймер генерирует только события 1-му DMA каналу. А уже по этим событиям 1-й канал управляет другим DMA-каналом который всё и делает.

Но сейчас посмотрел на карту регистров DMA и понял что тут так не получится - в STM32 у DMA регистр управления идёт первым, до регистра кол-ва пересылок и регистров адресов. И адрес внутри DMA-пересылки можно только инкрементировать, а декрементировать - нельзя. Так что - не получится их одним пакетом запрограммировать... :(((

 

Можно наверное изменить алгоритм:

Один DMA канал сконфигурить на пересылку в циклическом режиме в регистр управления GPIO (управление GPIO). Синхронизировать его от таймера. Каждая пересылка его будет менять состояние CS на противоположное.

А дальше - думать можно-ли на взаимных соединениях таймеров и DMA-каналов сделать автоматику. Вроде в STM32 таймеры могут посылать event-ы друг другу и разрешать работу друг друга.

Возможности DMA в STM32 очень бедные - трудно что-то сложное с помощью него сделать :((

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нет, не так. Я же вроде подробно разжевал в сообщении N8...

Да подробно, но я так и не понял как вы хотели с каждым новым тактом записывать разные данных, без участия прерываний(процессора).

Теперь понемногу доходит что имели ввиду, заложить все настройки в DMA1 и что бы каждом событии от таймера помощью авто инкремента, второй канал DMA программировался по разному.

 

И адрес внутри DMA-пересылки можно только инкрементировать, а декрементировать - нельзя

Это нужно было для того что бы выключить DMA канал перед записью размера транзакции ? записать и включить ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Теперь понемногу доходит что имели ввиду, заложить все настройки в DMA1 и что бы каждом событии от таймера помощью авто инкремента, второй канал DMA программировался по разному.

Это нужно было для того что бы выключить DMA канал перед записью размера транзакции ? записать и включить ?

Да, главная идея в том, чтобы всё делать при помощи DMA-каналов (stream-ов DMA в терминологии STM). Чтобы DMA-канал что-то сделал, его надо запрограммировать через его регистры конфигурации канала (через AHB-slave-интерфейс). Это может сделать любой AHB-bus-master: либо процессор либо другой DMA-канал либо ещё кто.

Значит если без CPU, то будем использовать для такого программирования другой DMA-канал (1-й), ему тоже должен кто-то толкнуть когда это надо делать (например - таймер).

Но толчок (event) от таймера один и значит запрограммировать надо одним пакетом (от одного события таймера). Поэтому - одна пакетная пересылка должна быть.

На NXP-шных МК я такое делал - там регистры конфигурации канала идут одним блоком и регистр управления (в котором и стоит бит разрешения канал) среди них последний.

На Tiva такое тоже теоретически возможно (хотя не пробовал), там тоже регистр управления последний в блоке.

А вот на STM32 сделали неудобно - он первый. Да если бы хотя-бы был режим не автоинкремента, а автодекремента - но тоже нету :((( Вобщем - кругом одни вилы тут, обрезано всё донельзя в этом STM32...

 

Можно конечно порыть в направлении - генерить два последовательных события от таймера двум разным DMA-каналам чтобы сначала записать регистры управления канала 2-у каналу DMA, а потом вторым событием - отдельно записать регистр DMA_SxCR с установленным битом разрешения работы. Но будет уже очень кучеряво ;) Хотя - дело Ваше ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Благодарю за помощь, теперь буду иметь ввиду, не записывать DMA_SxCR другим DMA точно не буду, да и сейчас задача чуть по проще выдать 120(const) байт с помощью дма и через каждые 5ть байт переключать CS (сам сигнал cs подается на вход(ETR) тактирование таймера ). В идеале бы

настроить DMA так что бы передача шла постоянно и без прерываний, сначала одни массив передали, потом другой и вернуться обратно на выдачу первого массива, вот с переключением обратно на первый массив есть вопросы можно ли сделать это аппаратно?

 

Так как тут количество байт между переключением CS константа, то это все можно настроить заранее и тогда надо будет только DMA включить, что и можно сделать другим DMA.

 

PS: интересно как поведет себя DMA если во время передачи менять регистр адресов, в даташите нечего не написано про то что DMA канал надо выключить при перезаписи адреса.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...