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

STM32F2xx - как покрасивее считывать внешнее АЦП черз SPI

Есть внешнее 16-битное АЦП с выходом SPI (конкретно LTC2383). Я выходом capture таймера генерю ему сигнал "начать преобразование". В ответ оно выставляет сигнал BUSY. После преобразования оно снимает сигнал BUSY и готово отдать мне 16 бит по SPI. Так вот вопрос - а можно ли, используя периферию STM32F2xx, сделать так, чтобы по этому сигналу BUSY автоматом, т.е. без участия программы, активизировался обмен по SPI? Из SPI данные будут забираться через DMA. Читал документацию, но ничего лучше чем "повесить BUSY на вход внешнего прерывания и в обработчике кидать фиктивный байт в SPI" пока не придумал. АЦП шустрое, не хотелось бы скакать в прерывание после каждого преобразования. Есть еще одна идея, но не буду ее пока излагать чтобы не ограничивать полет фантазии. Что можно намутить более хитрого?

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


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

Для чтения SPI всяко надо два канала DMA - один для передачи, другой для приёма. Каким образом их запускать автоматом - не знаю.

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


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

sclk постоянно выдавать тоже с таймера, spi в слэйв режим, busy как CS.

(или даже правильнее следать CNV high заведомо длиннее busy, а CNV low длительностью как раз 16 тактов, и CNV использовать как CS)

правда дергать 16ти разрядные АЦП за цифровые интерфейсы (клоки) во время преобразования не очень хорошо.

хотя можно пару диодов добавить между клоками и CNV чтобы они как лог. "ИЛИ" всегда 1 держали на входе клоков АЦП, пока идёт преобразование.

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


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

Скрещивал STM32discovery с ADS8361 (20бит слово). SPI процесора в slave. Управляющие сигналы генерятся таймерами а так же и тестовой сигнал проверки считивания. Результат через DMA в кольцевой буффер. До подключения самого АЦП руки не дошли, но с тест сигналов работало на ура. Код и осцилограммы выложил тут. Надеюсь поможет.

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


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

Я сделал так. Сигнал окончания преобразования DRDY от АЦП (ADS1251 24-битное) завел на внешнее прерывание ARM-процессора, затем проинициализированы два канала DMA (приемник и передатчик SPI). Таким образом, когда приходит прерывание от DRDY, то прямо в прерывании разрешаю передачу через DMA пустых 3-х байт (для тактирования SPI). После приема данных по SPI, DMA контроллер вызывает callback-функцию, в которой данные проходят через фильтры, масштабируются, и отображаются на дисплее. Т.е. вся идея состоит в том, чтобы обслуживание периферии возложить на DMA, а расчетную задачу и пользовательский интерфейс возложить на сам процессор.

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


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

Т.е. вся идея состоит в том, чтобы обслуживание периферии возложить на DMA, а расчетную задачу и пользовательский интерфейс возложить на сам процессор.
Вот и я так же хочу. Но мне надо набрать некоторое количество отсчетов, после чего приступить к их обработке. И хотелось, чтобы весь процесс накопления этих отсчетов происходил без вмешательства программы, получая лишь прерывание DMA в конце. Пока решил, как советовал -JonnS-, генерить таймером SCLK и CS, SPI в режим slave. Еще не разбирался детально - можно ли заставить таймер или комбинацию таймеров выдавать пачку импульсов по приходу внешнего сигнала, что-то похожее в описании попадалось.

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


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

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

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


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

че та я не понимаю.

у меня например ацп - ads1210

там ставишь в регистр DR число, которое соответствует частоте преобразование

и он пашет безо всякого вмешательства.

мне кажеца что большинство ацп именно таким образом и сделаны.

какой-то странный у вас кристал!

CS_ON(i);
// Настраиваем АЦП - длина слова 4 байта
ADS1210_WriteReg(0x64);// посылка 4-х байт в командный регистр с 3-го байта

ADS1210_WriteReg(0xc3);//3... BIAS=REFO=on,Two's=0,BiPol,MSByte,MSBit,SPI!!!	 0xc3	 
ADS1210_WriteReg(0x20);//2... System Self Calibration, gain = 1, channel = 1
// ADS1210_WriteReg(0x6c);//1...log2(TMR):3,DR:13; TMR=1..16 DR=ADCfrq*TMR/512/f(DATA)=Tmsr*625*TMR/32  	 0x6c
// ADS1210_WriteReg(0x17);//0...DR0-DR7

ADS1210_WriteReg(CMD1);//1...log2(TMR):3,DR:13; TMR=1..16 DR=ADCfrq*TMR/512/f(DATA)=Tmsr*625*TMR/32  	 
ADS1210_WriteReg(CMD0);//0...DR0-DR7


CS_OFF(i);

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


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

По приему всего блока данных DMA, может сгенерить прерывание.
Так это не проблема - проблема заставить проц этот блок данных через SPI "всосать" без вмешательства программы. Если бы я мог инициировать транзакцию DMA внешним сигналом - проблем мы не было.

 

какой-то странный у вас кристал!
Нет, не странный - просто другой. LTC2383. У него нет регистра DR. Он самодостаточен и slave. Дернул ногу - он преобразовал - можно считывать.

 

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


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

Если бы я мог инициировать транзакцию DMA внешним сигналом - проблем мы не было.

У ведь такая же ситуация, когда хотелось бы запустить DMA каналы автоматически. Но так и не нашел варианта такого запуска. Приходиться инициировать обмен по DMA перед каждой выборкой из АЦП. Это, конечно, дополнительные накладные расходы, но все равно получается приемлемо. Особенно при обработке готовности АЦП через FIQ.

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


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

Так это не проблема - проблема заставить проц этот блок данных через SPI "всосать" без вмешательства программы. Если бы я мог инициировать транзакцию DMA внешним сигналом - проблем мы не было.

От таймера DMA запускается?

Может, настроить таймер в capture mode от внешнего сигнала, а по защелкиванию формировать запуск транзакции DMA

Я в такие глубины еще не влезал, хотя тоже наверно придется.

Мне нечто подобное надо провернуть на MSP430

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


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

Для запуска DMA для вычитки данных из внешеного АЦП по SPI можно использовать любой таймер, запускаемый по сигналу конца преобразования ацп. Работаем с AD7690 - у них признак конца преобразования идет по низкому уровню на SDO. В даташите AD7690 есть пример, кода SDO с подтяжкой заводится и на вход данных SPI проца, и на IRQ. Вместо IRQ используем счетный вход таймера TIMx_ETR. Одна ДМА транзакция запускается без проблем, но вот для пачки транзакций - таймер сбивается данными при работе SPI. Приходится дизейблить вход TIMx_ETR до следущего CNV. Для этого пришлось использовать внешний аппаратный триггер.

Настраивать вход таймера через функции TIM_ETRClockMode1Config TIM_TIxExternalClockConfig.

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


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

В общем родил я такую стратегию:

 

TIM4_CH1 формирует короткие положительные импульсы запуска АЦП (CNV). Сигнал READY АЦП завел на TIM3_CH2. Канал №2 захвата/сравнения таймера 3 настраиваю на захват, спадающий фронт. TS таймера 3 настраиваю на TI2FP, Slave mode = Trigger, ARR = 35 (32 такта на выдачу 16 импульсов, 3 такта задержка модуля сравнения), OPM = 1. Канал №1 настраиваю в режим PWM2, он выдает импульс OC1REF длительностью 32 такта, этот канал делаю выходом TRGO. У таймера 2 настраиваю TS на ITR2 (TIM3_TRGO), Slave mode = Gated, ARR=1, Канал №3 захвата/сравнения настраиваю в режим PWM2, TIM2_CCR3 = 1, его выход внешней перемычкой завожу на вход SLK АЦП и на SPI3_SCK. Выход данных АЦП завожу на SPI3_MOSI. SPI3 настраиваю в режим SLAVE, RX_ONLY, DFF=1 (16бит).

 

Как я вижу работу этого клубка: По спадающему фронту сигнала BUSY на TIM2_CH2 запускается TIM3, который формирует одиночный импульс OC1REF длительностью 32 такта. Во время этого импульса разрешается работа TIM2, который успевает сформировать 16 импульсов на выходе TIM2_CH3. Эти импульсы тактируют SPI, из АЦП "высасываются 16 бит. После приема 16 бит инициируется транзакция DMA. После приема нужного количества отсчетов по прерыванию окончания пересылки DMA отключаю TIM4_CH1, преобразования прекращаются.

 

Что скажут специалисты, подводные камни есть?

 

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

 

Кстати, на будущее, такой вопрос - по картинке из даташита входы периферии подключены к портам всегда. Я правильно понимаю, что настроив SPI в режим slave я могу переключив GPIO_AFR порта SCK на другую периферию (скажем, таймер) формировать этой периферией на ножке сигналы и эти сигналы будут поступать на SCK? Ан нет - он же должен выбрать, с какой из ног, на которых возможно включение SCK, принимать этот сигнал. Значит и входы подключены только когда выбрана AF. Значит без внешней перемычки никак.

Хм. А почему тогда есть AF push-pull и AF open drain, но нет AF input?

Добавлено: разобрался - "The output buffer is driven by the signal coming from the peripheral (transmitter enable and data)". Т.е. направление определяется режимом периферии.

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


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

Что-то у вас на одну задачу куча таймеров тратится - неэффективно ;)

 

А разве в STM32 нельзя запускать DMA от таймера? В LPC я так делаю без проблем.

Я думаю ваш АЦП имеет известное заранее макс. время преобразования, следовательно - таймер генерящий сигналы запуска выдаёт импульсы CNV фиксированной частоты и заранее известно через какое время после начала импульса CNV будет выставлена готовность АЦП. Выставить генерацию DMA-запроса от этого-же таймера на это время и всё - получаем SPI в режиме мастер.

 

Другой способ - вообще обойтись без таймера, обойтись только SPI-мастером и двумя каналами DMA (tx, rx), но у АЦП должен быть вход CS разрешения передачи по SPI.

Сигнал MOSI заводим на CNV АЦП (возможно надо проинвертировать) и на вход CS АЦП, вых. данных АЦП - на MISO SPI.

Стартуем DMA мануально, сразу после старта генерится CNV. В передающем канале DMA создаём что-то типа:

периоды SCLK: 0123456789ABCDEF

_______ MOSI: 0111000000000000

_______ MISO: X---DDDDDDDDXXXX

D - бит данных, X - мусор (игнорим).

На 1-м такте SCLK формируется CNV, кол-во тактов от 1 до 4 выбрано так, что оно больше чем макс. время преобразования АЦП,

на тактах от 4 до B вытягиваются данные (кол-во разрядов здесь условно показано), суммарное кол-во тактов 0-F (и частота SCLK) определяет частоту выборок АЦП. DMA делаем с автоинициализацией.

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


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

В общем родил я такую стратегию:

Проблема имет место быть. Встроенные АЦП обычно имеют сложные автоматы сбора, но ограниченное качество и разрядность. А с внешними появляются проблемы с сканированием и доставкой данных в МК без участия ЦПУ. Бывало ставил CPLD для этих целей.

 

Как-то сложно у тебя выглядит, не хватило духу разобраться. SPI в slave и в МК и в АЦП, с клоком от таймера? Круть.

 

На поверхностный взгляд по спаду BUSY можно сгенерировать событие триггера таймера с вывода внешнего триггера TIM _ETR или захвата TIM_CH1 для запроса к DMA, а этим DMA пулять в SPI на выход. SPI в STM32 позволяет иметь 16 битный фрейм, поэтому одного запроса к DMA для записи в Tx SPI достаточно, чтобы вытащить слово из АЦП (естественно другим каналом DMA на Rx).

Предположительно по внешнему перепаду можно заставить один таймер STM32 на автомате выдать 5 или даже 6 запросов на DMA через задаваемые разные интервалы. Хотел попробовать, но руки не доходят и лень.

 

 

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


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

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

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

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

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

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

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

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

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

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