Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Почему передатчик SSC смещает влево на 1 бит передаваемое 32-битное слово
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
Bulat
Передатчик SSC отправляет 32-битные слова в непрерывном режиме с паузой 40мкс, частота тактирования 100 кГц.
По прерыванию (TXRDY) буфер передатчика обновляется. Непрерывную передачу с заданной паузой получить удалось,
но данные почему-то смещены в сторону старшего бита на 1. Почему так происходит?
CODE

//++++++++++++++++++++++++++--SSC--+++++++++++++++++++++++++++++++++++++++++++++
__ramfunc void SscHandler()
{
AT91C_BASE_SSC->SSC_THR = dat_buf; //обновление буфера передатчика
unsigned int dummy = AT91C_BASE_SSC->SSC_SR;
}

void AT91F_SSC_Conf ()
{
// Setup ssc
AT91F_SSC_CfgPMC(); /* Enable MCK clock */

// pio Special configuration
AT91F_SSC_CfgPIO();

//* Disable interrupts
AT91C_BASE_SSC->SSC_IDR = 0xfff;

//* Reset receiver and transmitter
AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST | AT91C_SSC_TXDIS ;

//* Define the Clock Mode Register
AT91C_BASE_SSC->SSC_CMR = 240; //100 кГц

//* Write the Transmit Clock Mode Register
AT91C_BASE_SSC->SSC_TCMR = (17 << 24) & AT91C_SSC_PERIOD | (5<<16) & AT91C_SSC_STTDLY |
AT91C_SSC_START_RISE_RF | (0x2 << 6) | AT91C_SSC_CKI | AT91C_SSC_CKO_DATA_TX | AT91C_SSC_CKS_DIV;

//* Write the Transmit Frame Mode Register
AT91C_BASE_SSC->SSC_TFMR = AT91C_SSC_FSOS_POSITIVE | (31<<0) & AT91C_SSC_DATLEN;
}


void AT91F_SSC_Start(void)
{

//* Open SSC interrupt

AT91C_BASE_AIC->AIC_SVR[AT91C_ID_SSC] = (unsigned int)SscHandler;
AT91C_BASE_AIC->AIC_SMR[AT91C_ID_SSC] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | SSC_INTERRUPT_LEVEL;
AT91C_BASE_AIC->AIC_IECR = (1UL << AT91C_ID_SSC);
AT91C_BASE_SSC->SSC_IER = AT91C_SSC_TXRDY;

AT91C_BASE_SSC->SSC_CR = AT91C_SSC_TXEN;
AT91C_BASE_SSC->SSC_THR = dat_buf;
}
//++++++++++++++++++++++++++--SSC--+++++++++++++++++++++++++++++++++++++++++++++
ramfunc int main(void)
{
AT91F_SSC_Conf();
AT91F_SSC_Start();
while(1) write(dat_buf);
}

Заранее благодарен!
aaarrr
Цитата(Bulat @ Dec 28 2009, 14:00) *
данные почему-то смещены в сторону старшего бита на 1. Почему так происходит?

Смещены относительно чего? Изложите чуть подробнее, что хотите получить, и что получается на самом деле.

Сейчас, как я понимаю, будет отрезан клок от одного бита, т.к. в конфигурации стоит Transmit Clock enabled only if TF High, но STTDLY + DATLEN > PERIOD.
Bulat
aaarrr
Слово смещено влево на 1 бит (то есть 32 бит теряется, а вместо первого бита 0),относительно записанного в переменной dat_buf. А как настроить, чтобы не был "отреза клок" от одного бита?
aaarrr
Цитата(Bulat @ Dec 28 2009, 21:37) *
А как настроить, чтобы не был "отреза клок" от одного бита?

Расширьте PERIOD.
Bulat
Цитата(aaarrr @ Dec 29 2009, 00:36) *
Расширьте PERIOD.

По Юзергайду "a period signal is generated at each 2 x (PERIOD+1) Transmit Clock", то есть STTDLY + DATLEN = 2 x (PERIOD+1)
STTDLY = 4, DATLEN = 31, отсюда PERIOD = 17. То есть я просто STTDLY уменьшил на 1 по сравнению с первоначальным вариантом в этом посте. Но как я заметил, при такой конфигурации SSC, как я привел в этом посте, значение поля STTDLY не влияет на паузу, так как PERIOD включает в себя длину 32-битного слова и 4-битную паузу, а в поле CKO у меня Transmit Clock only during data transfers. То есть, на выводе TK пояаляются имульсы только, когда в буфер загружается слово, а так как слово (32 бита) на 4 бита меньше периода TF (36), то и появляется пауза.
И всетаки, почему передаваемое слово смещается влево (в сторону старшего бита) на 1 относительно того, что я записываю в регистр THR?
Я прикрепил картинку с эпюрами. Желтый сигнал - вывод TK, розовый - TD. В буфер THR я записываю число 0х2000, а по эпюре видно, что 1 на выводе TD появилась только при 15 такте TK, то есть на выходе SSC уже число 0х4000 (смещено на 1 в сторону старшего).
Bulat
Первый тактовый импульс на желтой эпюре (смотри рисунок прикрепленный выше) соответствует не первому биту 32-битного слова, а значению вывода TD при отсутствии передачи, которое определяется полем DATDEF: Data Default Value. То есть, если DATDEF=1, то первый бит передаваемого слова будет равен 1. Почему так происходит? Получается, что SSC может передавать слова максимально длины 31 бит?
aaarrr
Цитата(Bulat @ Dec 29 2009, 13:24) *
Получается, что SSC может передавать слова максимально длины 31 бит?

Может и 32. Давайте сделаем так: добавьте к своей осциллограмме сигнал TF и напишите точную конфигурацию регистров SSC.
Bulat
Цитата(aaarrr @ Dec 29 2009, 20:50) *
Может и 32. Давайте сделаем так: добавьте к своей осциллограмме сигнал TF и напишите точную конфигурацию регистров SSC.


Точная конфигурацию регистров SSC:
CODE

//* Disable interrupts
AT91C_BASE_SSC->SSC_IDR = 0xfff;

//* Reset receiver and transmitter
AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST | AT91C_SSC_TXDIS ;

//* Define the Clock Mode Register
AT91C_BASE_SSC->SSC_CMR = 240; //100 кГц

//* Write the Transmit Clock Mode Register
AT91C_BASE_SSC->SSC_TCMR = (17 << 24) & AT91C_SSC_PERIOD | (4<<16) & AT91C_SSC_STTDLY | AT91C_SSC_START_RISE_RF |
(0x2 << 6) | AT91C_SSC_CKI | AT91C_SSC_CKO_DATA_TX | AT91C_SSC_CKS_DIV;

//* Write the Transmit Frame Mode Register
AT91C_BASE_SSC->SSC_TFMR = AT91C_SSC_FSOS_POSITIVE | (31<<0) & AT91C_SSC_DATLEN;


Осциллограмма TF представляет собой последовательность коротких импульсов с периодом 360 мкс, длительность импульса 10 мкс, то есть в период TF укладывается 36 бит - 32-бита данных и 4 бита паузы. К сожалению, сегодня не смогу снять эпюру с TF(
Bulat
Цитата(Bulat @ Dec 30 2009, 00:59) *
Осциллограмма TF представляет собой последовательность коротких импульсов с периодом 360 мкс, длительность импульса 10 мкс, то есть в период TF укладывается 36 бит - 32-бита данных и 4 бита паузы. К сожалению, сегодня не смогу снять эпюру с TF(

Прикрепляю картинку с тремя эпюрами, снятых на выводах передатчика TK,TD и TF. Период TF составляет 360 мкс, то есть 36 (32 импульсов бита данных и 4 бита паузы) с частотой 100кГц, как и должно быть. Бит данных (TD) смещен на 1 в сторону старшего бита (первым передается младший бит) по сравнению с тем, что было записано в буфер THR. Как я писал выше, первый тактовый импульс, а, следовательно, и первый передаваемый бит данных по TD соответствует значению поля DATDEF регистра TFMR, а не первому биту передаваемого слова. Как исключить из передачи этот лишний бит?
aaarrr
Странно, откуда вообще берутся клоки, если в поле CKG прописано "Transmit Clock enabled only if TF High", а TF во время передачи в нуле?

А что будет, если попробовать передать 0x2000 при такой конфигурации:
Код
//* Write the Transmit Clock Mode Register
AT91C_BASE_SSC->SSC_TCMR = (17 << 24) & AT91C_SSC_PERIOD | (4<<16) & AT91C_SSC_STTDLY |
    AT91C_SSC_START_RISE_RF | AT91C_SSC_CKO_DATA_TX | AT91C_SSC_CKS_DIV;

//* Write the Transmit Frame Mode Register
AT91C_BASE_SSC->SSC_TFMR = AT91C_SSC_FSOS_POSITIVE | (31<<0) & AT91C_SSC_DATLEN |
    (3 << 16) & AT91_SSC_FSLEN | AT91C_SSC_DATDEF;


P.S. У меня сейчас нет возможности проверить в железе, поэтому могу предложить только теоретические измышления.
Bulat
Цитата(aaarrr @ Jan 5 2010, 15:04) *
Странно, откуда вообще берутся клоки, если в поле CKG прописано "Transmit Clock enabled only if TF High", а TF во время передачи в нуле?

Судя по приведенным мною эпюрам в предыдущем ответе, клоки появляются только при загрузке буфера THR (AT91C_SSC_CKO_DATA_TX), а TF на синхронизацию никак не влияет. TF влияет только на период передаваемых слов и на паузу между словами (личные наблюдения).
Цитата
а TF во время передачи в нуле?

Да, TF во время передачи равен 0. Во время передачи TF=1, если AT91C_SSC_FSOS_HIGH, но в этом случае вообще ничего не работает)

Цитата
А что будет, если попробовать передать 0x2000 при такой конфигурации:
Код
//* Write the Transmit Clock Mode Register
AT91C_BASE_SSC->SSC_TCMR = (17 << 24) & AT91C_SSC_PERIOD | (4<<16) & AT91C_SSC_STTDLY |
    AT91C_SSC_START_RISE_RF | AT91C_SSC_CKO_DATA_TX | AT91C_SSC_CKS_DIV;

//* Write the Transmit Frame Mode Register
AT91C_BASE_SSC->SSC_TFMR = AT91C_SSC_FSOS_POSITIVE | (31<<0) & AT91C_SSC_DATLEN |
    (3 << 16) & AT91_SSC_FSLEN | AT91C_SSC_DATDEF;

Эпюры для этого варианта я прикрепил.
При добавлении поля (3 << 16) & AT91_SSC_FSLEN расширяется импульс TF, да еще и пауза между клоками в виде длинной 1, а мне ноль нужен. При добавлении поля AT91C_SSC_DATDEF первым битом TD является 1, что меня тоже не устраивает. Вообще, единственное, что меня не устраивает в конфигурации SSC, что я привел в предыдущем ответе, так это первый бит на выводе данных TD. Первым битом передаваемых данных как с вашей конфигурацией, так и с моей является значение поля DATDEF, из-за этого то и происходит смещение данных и потеря 32 бита, так как всего передается 32 бита. То есть, SSC почему-то после загрузки буфера THR сначало передает бит, который должен висеть на TD при отключенном передатчике SSC (поле DATDEF), а затем уже слово данных, но при этом на все это выделяется всего 32 клока! Как исключить передачу DATDEF при первом клоке?
Нажмите для просмотра прикрепленного файла
aaarrr
Цитата(Bulat @ Jan 5 2010, 14:35) *
...пауза между клоками в виде длинной 1, а мне ноль нужен.

Там не "1", а третье состояние, поэтому уровень в паузах будет зависеть от бита CKI. Но в любом случае снаружи потребуется pull-down, если нужен честный ноль.

Цитата(Bulat @ Jan 5 2010, 14:35) *
При добавлении поля AT91C_SSC_DATDEF первым битом TD является 1, что меня тоже не устраивает.

Я его специально добавил, чтобы видеть границы реального слова.

Цитата(Bulat @ Jan 5 2010, 14:35) *
То есть, SSC почему-то после загрузки буфера THR сначало передает бит, который должен висеть на TD при отключенном передатчике SSC (поле DATDEF), а затем уже слово данных, но при этом на все это выделяется всего 32 клока! Как исключить передачу DATDEF при первом клоке?

Он не "передает DATDEF", а почему-то неправильно гейтирует клок (со сдвигом на один такт). Сейчас попробуем разобраться.

Увы, работа CKO/CKG в мануале как-то обойдена стороной sad.gif

Что можно еще попробовать:
1. Привязать старт к уровню вместо фронта. Возможно, это изменит поведение CKO.
2. Отказаться от CKO и использовать вместо него CKG:
Код
//* Write the Transmit Clock Mode Register
AT91C_BASE_SSC->SSC_TCMR = (17 << 24) & AT91C_SSC_PERIOD | (4<<16) & AT91C_SSC_STTDLY |
    AT91C_SSC_START_RISE_RF | (0x1 << 6) | AT91C_SSC_CKI | AT91C_SSC_CKS_DIV;

//* Write the Transmit Frame Mode Register
AT91C_BASE_SSC->SSC_TFMR = AT91C_SSC_FSOS_POSITIVE | (31<<0) & AT91C_SSC_DATLEN |
    (3 << 16) & AT91_SSC_FSLEN | AT91C_SSC_DATDEF;

Возможно, придется отинвертировать TF, если передатчик действительно отказывается работать при 0x1 в CKG:
Код
//* Write the Transmit Clock Mode Register
AT91C_BASE_SSC->SSC_TCMR = (17 << 24) & AT91C_SSC_PERIOD | (4<<16) & AT91C_SSC_STTDLY |
    AT91C_SSC_START_FALL_RF | (0x2 << 6) | AT91C_SSC_CKI | AT91C_SSC_CKS_DIV;

//* Write the Transmit Frame Mode Register
AT91C_BASE_SSC->SSC_TFMR = AT91C_SSC_FSOS_NEGATIVE | (31<<0) & AT91C_SSC_DATLEN |
    (3 << 16) & AT91_SSC_FSLEN | AT91C_SSC_DATDEF;

3. Если ничего из перечисленного не поможет, задействовать еще и приемник.
Bulat
Цитата(aaarrr @ Jan 5 2010, 17:43) *
1. Привязать старт к уровню вместо фронта. Возможно, это изменит поведение CKO.
Пробовал, ничего не изменилось.
Цитата(aaarrr @ Jan 5 2010, 17:43) *
2. Отказаться от CKO и использовать вместо него CKG:
Код
//* Write the Transmit Clock Mode Register
AT91C_BASE_SSC->SSC_TCMR = (17 << 24) & AT91C_SSC_PERIOD | (4<<16) & AT91C_SSC_STTDLY |
    AT91C_SSC_START_RISE_RF | (0x1 << 6) | AT91C_SSC_CKI | AT91C_SSC_CKS_DIV;

//* Write the Transmit Frame Mode Register
AT91C_BASE_SSC->SSC_TFMR = AT91C_SSC_FSOS_POSITIVE | (31<<0) & AT91C_SSC_DATLEN |
    (3 << 16) & AT91_SSC_FSLEN | AT91C_SSC_DATDEF;

Вывод TK вообще не подает признаков жизни.
Цитата(aaarrr @ Jan 5 2010, 17:43) *
Возможно, придется отинвертировать TF, если передатчик действительно отказывается работать при 0x1 в CKG:
Код
//* Write the Transmit Clock Mode Register
AT91C_BASE_SSC->SSC_TCMR = (17 << 24) & AT91C_SSC_PERIOD | (4<<16) & AT91C_SSC_STTDLY |
    AT91C_SSC_START_FALL_RF | (0x2 << 6) | AT91C_SSC_CKI | AT91C_SSC_CKS_DIV;

//* Write the Transmit Frame Mode Register
AT91C_BASE_SSC->SSC_TFMR = AT91C_SSC_FSOS_NEGATIVE | (31<<0) & AT91C_SSC_DATLEN |
    (3 << 16) & AT91_SSC_FSLEN | AT91C_SSC_DATDEF;

Аналогично, на TK нет сигнала без кофигурации CKO. Попробовал к этой конфигурации просто добавить CKO_CONTINOUS, эпюры приведены
на прикрепленной картинке. При такой конфигурации по TD действительно передается такое же слово, что и записано в THR 0х2000 (без смещения), но при этом во время паузы между словами передаются синхроимпульсы, да к тому же на время паузы клок не останавливается, что меня не устраивает. Складывается впечатления, что CKG вообще не оказывает влияние на передатчик. К тому же поле CKG почему-то забыли описать в хедере AT91SAM7S256.h.
Цитата(aaarrr @ Jan 5 2010, 17:43) *
3. Если ничего из перечисленного не поможет, задействовать еще и приемник.

То есть вывод TF настроить как вход, а синхросигналы подавать с вывода RF?
aaarrr
Цитата(Bulat @ Jan 6 2010, 10:46) *
Попробовал к этой конфигурации просто добавить CKO_CONTINOUS, эпюры приведены на прикрепленной картинке. При такой конфигурации по TD действительно передается такое же слово, что и записано в THR 0х2000 (без смещения), но при этом во время паузы между словами передаются синхроимпульсы, да к тому же на время паузы клок не останавливается, что меня не устраивает.

Зато теперь можно выкрутиться, добавив одногейтовый AND для клока.

Цитата(Bulat @ Jan 6 2010, 10:46) *
Складывается впечатления, что CKG вообще не оказывает влияние на передатчик. К тому же поле CKG почему-то забыли описать в хедере AT91SAM7S256.h.

Да, все правильно: судя по картинке, он действует только на внутренний Transmit Clock. А вот с CKO явно что-то не так.
Беда в том, что при нормальной работе (т.е. общении с кодеками) эти функции никому особо не нужны.

Цитата(Bulat @ Jan 6 2010, 10:46) *
То есть вывод TF настроить как вход, а синхросигналы подавать с вывода RF?

Т.е. настроить приемник так, чтобы на RK сформировалась нужная картина, а передатчик запустить от сигналов приемника с нужным смещением.

Да, и раз уж пошла такая пьянка: не влияет ли бит MSBF на смещение данных?
Bulat
Цитата(aaarrr @ Jan 6 2010, 16:39) *
Зато теперь можно выкрутиться, добавив одногейтовый AND для клока.

Вы имеете в виду аппаратный AND? Можно поподробнее?).

Цитата(aaarrr @ Jan 6 2010, 16:39) *
Да, и раз уж пошла такая пьянка: не влияет ли бит MSBF на смещение данных?

Смещение данных всеравно есть, просто данные перевернуты, то есть теперь теряется первый бит.

Я решил сделать проще, раз от клока для DATDEF никуда не деться, то использовать поле для передачи первого бита слова.
То есть, перед записью слова в THR я формирую слово данных без первого бита, сещенное на 1 в сторону младшего бита.
А в зависимости от значения первого бита слова данных я изменяю поле DATDEF. В принципе, эта схема у меня работает, но для слов,
у которых первый байт равен 0xfe и 0xff происходит сбой алгоритма. По идее, если первый байт передаваемого слова равен 0xfe,
то в поле DATDEF записывается 0, а если первый байт 0xff, то 1. У меня же происходит все наоборот, но только для этих двух значений,
все остальные варианты слов данных передаются нормально.
CODE


__ramfunc void SscHandler()
{
jj=0; //dat_buf пуст

if(fb) AT91C_BASE_SSC->SSC_TFMR |= AT91C_SSC_DATDEF; //Установка поля DATDEF при fb=1
(первый бит передаваемого слова равен 1)
else AT91C_BASE_SSC->SSC_TFMR &= ~(AT91C_SSC_DATDEF);

AT91C_BASE_SSC->SSC_THR = dat_buf;

unsigned int dummy = AT91C_BASE_SSC->SSC_SR;
}

void AT91F_SSC_Conf ()
{
...

//* Write the Transmit Clock Mode Register
AT91C_BASE_SSC->SSC_TCMR = (17 << 24) & AT91C_SSC_PERIOD | (4<<16) & AT91C_SSC_STTDLY | AT91C_SSC_START_RISE_RF |
AT91C_SSC_CKI | AT91C_SSC_CKO_DATA_TX | AT91C_SSC_CKS_DIV;

//* Write the Transmit Frame Mode Register
AT91C_BASE_SSC->SSC_TFMR = AT91C_SSC_FSOS_POSITIVE | (31<<0) & AT91C_SSC_DATLEN;
}

//Первоначальный запуск передатчика
void AT91F_SSC_Start(void)
{

//* Open SSC interrupt
AT91C_BASE_AIC->AIC_SVR[AT91C_ID_SSC] = (unsigned int)SscHandler;
AT91C_BASE_AIC->AIC_SMR[AT91C_ID_SSC] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | SSC_INTERRUPT_LEVEL;
AT91C_BASE_AIC->AIC_IECR = (1UL << AT91C_ID_SSC);
AT91C_BASE_SSC->SSC_IER = AT91C_SSC_TXRDY;

AT91C_BASE_SSC->SSC_CR = AT91C_SSC_TXEN;

if(fb) AT91C_BASE_SSC->SSC_TFMR |= AT91C_SSC_DATDEF; //Установка поля DATDEF при fb=1
(первый бит передаваемого слова равен 1)
else AT91C_BASE_SSC->SSC_TFMR &= ~(AT91C_SSC_DATDEF);

AT91C_BASE_SSC->SSC_THR = dat_buf;

}

__ramfunc void Write_TRA()
{
//Считывание 32-битного слова данных из UDP
unsigned int byte1 = regUDP->UDP_FDR[AT91C_EP_OUT];
unsigned int byte2 = regUDP->UDP_FDR[AT91C_EP_OUT];
unsigned int byte3 = regUDP->UDP_FDR[AT91C_EP_OUT];
unsigned int byte4 = regUDP->UDP_FDR[AT91C_EP_OUT];
fb = byte1&0x1; //Запись значения первого бита слова
byte1 = byte1 >> 1; //Избавляемся от первого бита слова данных

dat_buf = (byte4<<23)|(byte3<<15)|(byte2<<7)|byte1; //подготовка 31 бита слова данных,
за исключением первого бита
jj = 1; //dat_buf заполнен

if(ii==1) {AT91F_SSC_Start(); ii=0;} //Первоначальный запуск передатчика,
далее он не останавливается

length = length-5;
}

int main(void)
{
while(1)
{
if(jj==0) Write_TRA(); //если буфер передатчика SSC пуст
}
}
aaarrr
Цитата(Bulat @ Jan 6 2010, 16:25) *
Вы имеете в виду аппаратный AND? Можно поподробнее?).

Ну да, аппаратный (1G08 какой-нибудь). Заводим на него TF и TK с последней картинки, и получаем клок с нужными паузами на выходе.

Цитата(Bulat @ Jan 6 2010, 16:25) *
Я решил сделать проще, раз от клока для DATDEF никуда не деться, то использовать поле для передачи первого бита слова.

ИМХО, не стоит так делать: во-первых, сложно, во-вторых - не факт, что поведение клока в какой-то момент не исправят.
Bulat
Цитата(aaarrr @ Jan 6 2010, 18:45) *
Ну да, аппаратный (1G08 какой-нибудь). Заводим на него TF и TK с последней картинки, и получаем клок с нужными паузами на выходе.

Спасибо большое!) Добавил AND и получил клок тот, что мне надо. Теперь передаются те данные, что мне нужны)
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.