ARM Cortex-M4: внешняя шина, smc #5

DSCN556756565

Параллельный интерфейс микроконтроллеров, известный как EBI, используется почти во всех проектах с TFT дисплеями, внешней памятью и т.п. Он обладает высокой скоростью передачи и большим адресуемым объемом.

 
 

Теория

Про параллельный интерфейс я писал ранее и затронул конкретное семейство контроллеров SAM3X. Он ничуть не изменился: шина данных, шина адреса и пара управляющих сигналов.

Ashampoo_Snap_2014.10.13_23h28m55s_008_-e1413459436843

 

Все задержки, как правило, настраиваются под конкретное устройство. Максимальная ширина шины данных: 16бит, а ширина адреса: 24бит — это позволяет адресовать 32МБайта. Кстати, многие считают этот интерфейс асинхронным, однако нам ничего не мешает использовать PCK для генерации тактовой частоты в порт.

Устройство

Внешняя шина управляется контроллером SMC, который фактически выводит наружу внутренние линии связи между ЦП и периферией.

smc

Контроллер разбит на четыре канала, каждый из которых настраивается отдельно. Он предоставляет нам полноценных шины адреса и данных, а также ряд управляющих:

  • NRD — сигнал чтения. [выход]
  • NWE — сигнал записи. [выход]
  • NCS[3:0] — четыре линии выборки устройства, привязанных к каналам. [выход]
  • NWAIT — сигнал ожидания от устройства. [вход]

Первое, с чего нужно начать: включить систему тактирования:

1
PMC->PMC_PCER0 = PMC_PCER0_PID10;

Одним из основных регистров SMC является SMC_MODE, задающий следующие параметры.

Параметр Описание
SMC_MODE_DBW_8_BIT Инициализация шины данных 8бит
SMC_MODE_DBW_16_BIT Инициализация шины данных 16бит
SMC_MODE_WRITE_MODE Использовать сигнал NWE
SMC_MODE_READ_MODE Использовать сигнал NRD
SMC_MODE_EXNW_MODE_FROZEN Сигнал WAIT будет останавливать передачу
SMC_MODE_EXNW_MODE_READY Сигнал WAIT будет завершать передачу

Для стандартной инициализации интерфейса с шириной шины данных 8бит на канале CS0 код будет следующий:

1
2
SMC0->SMC_WPMR = 0x534D43; //Очень черная магия
SMC0->SMC_CS_NUMBER[0].SMC_MODE = SMC_MODE_DBW_8_BIT | SMC_MODE_WRITE_MODE | SMC_MODE_READ_MODE;

Ashampoo_Snap_2015.01.06_19h00m43s_003_ Вы можете использовать всю шину 16бит, но это не увеличит скорость передачи точно в два раза. Возникает проблема выравнивая данных.

Сигнал WAIT, в частности его режим FROZEN, может очень помочь, если ваше устройство не может постоянно работать на шине. Достаточно установить 0 на линии, и передача приостановится.

Следующим регистром настройки будет SMC_CYCLE, который устанавливает количество тактов MCLK для записи или чтения 1-ед. данных.

Параметр (Atmel Studio) Описание
SMC_CYCLE_NRD_CYCLE(x) x — циклы чтения
SMC_CYCLE_NWE_CYCLE(x) x — циклы записи

Если ваше устройство — SRAM, то необходимо смотреть параметр taa на чтение и запись, а затем разделить его на период тактовой частоты. Почти для всех 10ns SRAM и частоте контролера >100MHz подойдет следующая конфигурация:

1
SMC0->SMC_CS_NUMBER[0].SMC_CYCLE = SMC_CYCLE_NRD_CYCLE(4) | SMC_CYCLE_NWE_CYCLE(2);

Вы можете заметить, что циклы чтения в два раза больше циклов записи — это связано с тем, что данные от SRAM приходят не сразу, а через определенное время: при единичном чтении — это проблема.

Регистры SMC_SETUP и SMC_PULSE задают длительности и задержки управляющих сигналов.
Ashampoo_Snap_2015.01546.07_11h00m52s_005_

SMC_SETUP (Atmel Studio) Значение
SMC_SETUP_NRD_SETUP(x) x — циклы до установки NRD
SMC_SETUP_NCS_RD_SETUP(x) x — циклы до установки CS и NRD
SMC_SETUP_NWE_SETUP(x) x — циклы до установки NWE
SMC_SETUP_NCS_WE_SETUP(x) x — циклы до установки CS и NWE
SMC_PULSE (Atmel Studio) Значение
SMC_PULSE_NRD_PULSE(x) x — длина импульса NRD
SMC_PULSE_NCS_RD_PULSE(x) x — длина импульса NCS и NRD
SMC_PULSE_NWE_PULSE(x) x — длина импульса NWE
SMC_PULSE_NCS_WE_PULSE(x) x — длина импульса NCS и NWE

Здесь вам необходимо внимательно просмотреть документацию на SRAM или что-то другое. Диаграмма сигналов для чтения выглядит точно так же.

Заметьте, что всегда должно выполнятся условие: xcycle = 1 + xpulse + xsetup И в основном, 10-12ns SRAM не требуют ожидания перед установкой сигналов:

1
2
SMC0->SMC_CS_NUMBER[0].SMC_SETUP = SMC_SETUP_NCS_RD_SETUP(0) | SMC_SETUP_NCS_WR_SETUP(0) | SMC_SETUP_NRD_SETUP(0) | SMC_SETUP_NWE_SETUP(0);
SMC0->SMC_CS_NUMBER[0].SMC_PULSE = SMC_PULSE_NCS_RD_PULSE(3) | SMC_PULSE_NCS_WR_PULSE(1) | SMC_PULSE_NRD_PULSE(3) | SMC_PULSE_NWE_PULSE(1);

Кстати, если вам необходимо только передавать данные во внешнее устройство или только принимать, можете не устанавливать биты WRITE_MODE или READ_MODE, тогда всеми операциями будет руководить CS сигнал.

Подключение 

Внешним устройством может быть как и SRAM, так вообще все, что угодно. (ПЛИС, например) От выбранной ширины шины данных зависит способ подключения:
Ashampoo_Snap_2015.01.07_20h07m545439s_006_
Заметьте, что при использовании 16бит интерфейса добавляется еще один сигнал: NBS1. Благодаря ему и A0 у нас будет возможность по-байтово работать с данными и не выравнивать их. Сигналы: WE, RD, CS, WAIT — инверсные.

Настройка портов

Как и для всей периферии, в ARM нужно настроить PIO для каждого канала, а линий там куча. Я вывел все необходимое на отладочной плате:

Ashampoo_Snap_2015.01.08_18h05m40s_007_

 

Инициализация портов довольно трудоемкое дело. Я приложил файл здесь.

Использование

Нам остается просто объявить указатель на тот или иной канал:

1
uint8_t* ptr =  (uint8_t*)EBI_CS0_ADDR;

За константой скрывается адрес 0x60000000 — это наше внешнее устройство. Пользуемся как хотим :-) .

Проверка

Хочу заметить, что параллельный интерфейс находится в адресном пространстве МК также на правах памяти, поэтому с ним можно работать как с массивом/переменной, использовать функции memcpy и даже исполнять оттуда код.

Но я возьму довольно простой пример: подключить к нему Delta-Sigma ЦАП, созданный на ПЛИС. Задача проста: нам нужно отправлять сэмплы PCM файла ЦАП-у с заданной частотой дискретизации.Ashampoo_Snap_2015.01.08_20h58m07s_009_
Здесь нам даже не понадобиться тактовый сигнал и вся шина адреса. Со стороны МК требуется отправлять сэмплы по прерыванию таймера.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdlib.h>
#include "snd.h"
#include <stdio.h>
 
uint8_t *au = (uint8_t*)EBI_CS1_ADDR; //ЦАП висит на CS1
uint32_t i = 0;
//.........................................................
//......................................................
 
initPIO();
PMC->PMC_PCER0 = PMC_PCER0_PID10 | PMC_PCER0_PID23; //Включаем SMC и TC0
 
SMC0->SMC_WPMR = 0x534D43; //Настраиваем SMC
SMC0->SMC_CS_NUMBER[1].SMC_CYCLE = SMC_CYCLE_NRD_CYCLE(4) | SMC_CYCLE_NWE_CYCLE(2);
SMC0->SMC_CS_NUMBER[1].SMC_PULSE = SMC_PULSE_NCS_RD_PULSE(3) | SMC_PULSE_NCS_WR_PULSE(1) | SMC_PULSE_NRD_PULSE(3) | SMC_PULSE_NWE_PULSE(1);
SMC0->SMC_CS_NUMBER[1].SMC_SETUP = SMC_SETUP_NCS_RD_SETUP(0) | SMC_SETUP_NCS_WR_SETUP(0) | SMC_SETUP_NRD_SETUP(0) | SMC_SETUP_NWE_SETUP(0);
SMC0->SMC_CS_NUMBER[1].SMC_MODE = SMC_MODE_DBW_8_BIT | SMC_MODE_WRITE_MODE | SMC_MODE_READ_MODE;
 
TC0->TC_WPMR = 0x54494D; //Настраиваем таймер на частоту 22.5кГц
TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_CLKDIS;
TC0->TC_CHANNEL[0].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1 | TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_CPCTRG;
 
TC0->TC_CHANNEL[0].TC_RC = 2500; //?
TC0->TC_CHANNEL[0].TC_RA = 0;
TC0->TC_CHANNEL[0].TC_RB = 0;
TC0->TC_CHANNEL[0].TC_IER = TC_IER_CPCS;
TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_CLKEN;
TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_SWTRG;
NVIC_EnableIRQ(TC0_IRQn);

На 120MHz вы должны услышать музыку. Обработчик:

1
2
3
4
5
6
7
8
9
void TC0_Handler(void) {
  au[0] = sound[i];
  ++i;
  if (i>sizeof(sound)) i=0;
 
  register uint32_t dummy;
  dummy = TC0->TC_CHANNEL[0].TC_SR;
  (void) dummy ;
}

Файл с PCM можно взять здесь. Работа системы продемонстрирована на видео ниже:

Это, пожалуй, не лучшее использование EBI интерфейса. :-) Его ниша — внешняя SRAM, процессоры-обработчики, TFT дисплеи. Я же пробовал подключать к нему одновременно видеопроцессор и FPGA, результатом я оказался доволен. Развитие системы может несомненно продолжаться!

ATSAM4 пересылает в видеопроцессор спрайты и т.п по кадровому синхроимпульсу. А в FPGA почти постоянно, в ней находится FIFO. Вся система работает без DMA, потому как у SAM4C его нет :) Вместо него я использую модифицированную функцию memcpy.


Все части

Вы можите оставить комментарий, или поставить трэкбек со своего сайта.

Написать комментарий

XHTML: Вы можете использовать эти теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Bug Report
Локализовано: шаблоны Wordpress