|
глобальные грабли с spi1 в lpc214x, не работает на прием |
|
|
|
Sep 29 2006, 06:56
|
Местный
  
Группа: Свой
Сообщений: 366
Регистрация: 5-09-06
Из: Санкт-Петербург
Пользователь №: 20 107

|
Уважаемые,
Я тут наткнулся на следующие грабли - запускаю СПИ1 в режиме мастера - CPOL = 1, CPHA = 1, разрешаю прерывания - SSPIMSC = 8 (прерывания, когда очередь на передачу на половину пуста).
Стартую СПИ1 так - 1. очищаю приемную очередь: while( SSPSR & (1<<2)) __dummy = SSPDR;
2. Записываю 1 байт в очередь SSPDR = *out_buff++;
3. Разрешаю прерывания.
Осциллом смотрю на все ноги. На ногу MISO подаю данные, которые знаю. Однако ножку SSEL1 дергаю сам. Вижу следующее - Посылается один байт. Вызывается обработчик прерывания.
В обработчике прерывания я 1. проверяю - есть ли данные в приемной очереди : while(SSPSR & (1<<2)) *in_buff++ = SSPDR;
2. Набиваю очередь на передачу while(SSPSR & (1<<1)) SSPDR = *out_buff++;
3. Естественно, контролирую количество байт, но это не затрагивает обращение к переферийным регистрам.
Теперь собственно ГРАБЛИ: 1. В обработчике прерывания бит RNE (receive FIFO not empty) никогда не бывает установлен в единицу. А это значит, что ничего не принято - а это не понятно почему. Тем не менее, при запуске СПИ1 в приемной очереди есть данные всегда.
2. Передающая очередь никогда не бывает размером больше 2х - т.е. цикл while(SSPSR & (1<<1)) SSPDR = *out_buff++; выполняется не более 2х раз!!! (размер очереди - 8)
мож кто сталкивался с подобным?
Заранее благодарствую
|
|
|
|
|
Oct 2 2006, 08:02
|
Местный
  
Группа: Свой
Сообщений: 366
Регистрация: 5-09-06
Из: Санкт-Петербург
Пользователь №: 20 107

|
Цитата(zltigo @ Sep 30 2006, 01:20)  Честно прочитал четыре раза. После процесса иницализации и 'стартую 1 2 3' не смог ничего понять из дальнейших действий :-( С 213x/4x работаю из "проблем" с FIFO только одна - нет возможности сбросить его содержимое без тупого вычитывания. Все испробованые режимы соответствуют документации. Возможные грабли весьма интересуют посему просьба описать более ясно ситуацию - попробую повторить. Грабли такие - 1. Размер очереди на передачу - по документации она == 8, у меня ее размер, вычисленный путем проверки флага в SSPSR получается не более 2х. 2. Флаг наличия данных в приемной очереди никогда не бывает равен 1. Т.е. такое впечатление, что очередь всегда пуста.
|
|
|
|
|
Oct 2 2006, 10:16
|
Местный
  
Группа: Свой
Сообщений: 366
Регистрация: 5-09-06
Из: Санкт-Петербург
Пользователь №: 20 107

|
Цитата(zltigo @ Oct 2 2006, 13:08)  Цитата(diwil @ Oct 2 2006, 11:02)  Грабли такие -
Не совсем понятны условия в которых сие проявляется. В меру своего понимания описанного явления попробую что-то подобное сочинить (просто самому интересно) и проверить. Код такой - Код extern char *in, *out;
void __irq spp_isr(void) { while(SSPSR & (1<<2) ) *in++ = SSPDR;
while(SSPSR & (1<<1)) SSPDR = *out++; }
void ssp_start(char *inb, char *outb) { int dummy; in = inb; out = outb+1;
while(SSPSR & (1<<2) ) dummy = SSPDR;
SSPIMSC = 12; SSPDR = *outb; } В обработчике прерываний первый цикл никогда не выполняется, второй - запихивает по два байта в SSPDR.
|
|
|
|
|
Oct 2 2006, 11:36
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Урвал минутку, посмотрел. Для начала, так: Код while(SSPSR & (1<<1)) SSPDR = *out++; Делать нельзя, дело в том, что обращение к периферии очень медленное (не менее 8 тактов на обращение) и на приличных скоростях SPI SSPDR удается в общем случае загружать медленне, чем он разгружается :-( Даже простейший вариант SSPDR = i++; Успевает (проверено электроникой) даже на 15Mhz "залить" в 8ми элементное FIFO 32!!! байта до его "переполнения" Глубина FIFO действительно 8 элементов и при приеме из 32 переданных вычитываются первые 8. Эксперимент проводился на 2148 без индекса 01 - возможно с 01 картина будет несколько иная. Так что заливать придется, например, с огдядкой :-( на переполнение приемного FIFO.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 2 2006, 12:09
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(diwil @ Oct 2 2006, 14:46)  хм...
байты по СПИ1 передаются правильно... смотрел осциллом и на другой конец приходят прально. У меня для начала однозначно захлебывается уже передача. Цитата тогда ладно... допустим он по прерываниям не будет работать... Почему не будет! будет! А что Вы хотели сказать (ну хотя-бы HEX, если биты влом описать) этим SSPIMSC = 12; Выбирая прерывания при полупустых обеих FIFO зачем оба-то, тем более для мастера? Цитата а если сделать как в филипсовском примере? Не читал "примеры" - давно "завязал" :-( c чтением. Я честно говоря просто не могу понять конечную цель, чего надо достигнуть??? Давайте так: 1. Master - это понятно. 2. На какой скорости? 3. Обмен пакетный? Одиночными фреймами? 4. Нарезка SSELом на фреймы нужна?
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 2 2006, 13:02
|
Местный
  
Группа: Свой
Сообщений: 366
Регистрация: 5-09-06
Из: Санкт-Петербург
Пользователь №: 20 107

|
Цитата(zltigo @ Oct 2 2006, 16:09)  Давайте так: 1. Master - это понятно. 2. На какой скорости? 3. Обмен пакетный? Одиночными фреймами? 4. Нарезка SSELом на фреймы нужна? 1. Мастер и только мастер 2. PCLK/2 : pclk = 14.7456/2 MHz итого сторость СПИ1 около 1МГц 3. нет. хочу передавать и принимать (одновременно) данные от 37 до 535 байт. при этом, на время всей передачи SSEL должен быть низким. 4. нет
|
|
|
|
|
Oct 2 2006, 14:58
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(diwil @ Oct 2 2006, 16:02)  2. PCLK/2 : pclk = 14.7456/2 MHz итого сторость СПИ1 около 1МГц "Скорость" SPI таки в битах, посему ~7,5MHz, что является достаточно быстрым и попадает в неприятную зону, когда уже не успеть (практически это в Вашем случае 128 тактов процессора с момента полупустого FIFO)забивать и вычитывать FIFO со скоростью обеспечивающей отсутствие аппаратного дергания SSEL. SSEL - софтом дергать надо будет. Кроме того это где-то надо думать использовать/не использовать прерывание - ибо прерывание опять будет приходить через 128 тактов - и накладные расходы на обслуживание будут немалые. Ответ на вопрос по использованию прерывания зависит от прочих системных решений. Цитата 3. нет. хочу передавать и принимать (одновременно) данные от 37 до 535 байт. при этом, на время всей передачи SSEL должен быть низким. Т.е. в какой-то момент времени в буфере передачи появляетя порция от 37 до 535 байт и это является сигналом к началу процесса. Принятые байты складываются в приемный буфер и все разборки "потом". Самый тупой вариант SSEL софтом управляемый, байты запихиваются в FIFO и со сдвигом на несколько засунутых в FIFO байт считываются. Прерывания от SPI не используются. Времени занимает много, но при разрешенных прерываниях и/или наличии операционки все будет работать с минимальными суммарными накладными расходами. Набросать такой вариант? Или с прерываниями, если нужно обеспечить более высокую равномерность работы с SPI?
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 2 2006, 16:17
|
Местный
  
Группа: Свой
Сообщений: 366
Регистрация: 5-09-06
Из: Санкт-Петербург
Пользователь №: 20 107

|
Цитата(zltigo @ Oct 2 2006, 18:58)  Самый тупой вариант SSEL софтом управляемый, байты запихиваются в FIFO и со сдвигом на несколько засунутых в FIFO байт считываются. Прерывания от SPI не используются. Времени занимает много, но при разрешенных прерываниях и/или наличии операционки все будет работать с минимальными суммарными накладными расходами. Пасибо большое. добрался до платы. Разобрался. Было: 1. скорость СПИ1 (в битах) около 2МГц 2. За время цикла записи числа в ФИФУ она успевает вычищаться и весь блок передается в одном цикле обработчика прерывания. 3. аппаратный SSEL1 успевает дернуться после записи каждого байта в фифу. 4. И да, когда заканчиваются данные на запись, то начинается чтение из приемной фифы. В результате я там имею первые 8 байт. Похоже, что прерывание отменяются, ибо макс. внутренний буфер (>4K) , будет накапливаться за 16 мс, что допустимо. еще раз спасибо Дима
|
|
|
|
|
Oct 2 2006, 17:33
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Простейший вариант без прерывания. На частоте SPI ~7.5MHz и ниже FIFO не успевает опустошаться и SSEL не дергается, как и требовалось. Если ~15MHz, то уже не успевает загрузка+разгрузка SSEL дергается - надо софтово управлять, как и в случае разрешенных прерываний. Код //--------------------------------------------------------------------------- // //--------------------------------------------------------------------------- int init_SPI1( void ) { // Prescaler = 2 (Maximum Clock for Master) SSPCPSR_bit.CPSDVSR = 2;
// Configure Pin Connect Block PINSEL1_bit.P0_17 = 0x2; // SCK1 PINSEL1_bit.P0_18 = 0x2; // MISO1 PINSEL1_bit.P0_19 = 0x2; // MOSI1 PINSEL1_bit.P0_20 = 0x2; // SSEL1
SSPCR0_bit.FRF = 0; // SPI Mode SSPCR0_bit.DSS = (8-1); // 8bit Transfer SSPCR0_bit.CPOL = 1; // Polarity SSPCR0_bit.CPHA = 1; // Phase SSPCR0_bit.SCR = (4-1); // Divider
// Device selected as master SSPCR1_bit.MS = 0; // Master SSPCR1_bit.SSE = 1; // Global Enable
for( int i = 0; i < 8; i++ ) { ulong dummy = SSPDR; // Clear the RxFIFO dummy = dummy; }
return( 0 ); // Ok }
//--------------------------------------------------------------------------- BYTE ex_tx_buf[37] = {0,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 ,30,31,32,33,34,35,36}; BYTE ex_rx_buf[37]; #define EX_TX_BYTE {SSPDR = *tx_ptr++; nn--;} #define EX_RX_BYTE *rx_ptr++ = SSPDR
// Experiment //--------------------------------------------------------------------------- void SPI1_experiment( int size ) { int nn=size; BYTE *tx_ptr = ex_tx_buf; BYTE *rx_ptr = ex_rx_buf; register BYTE stat;
memset( rx_ptr, 0xFF, size );
// ENTER_CRITICAL(); // { do { // Забиваем FIFO до упора - хорошо для прерывистого процесса if( (stat = SSPSR) & SSPSR_TNF ) EX_TX_BYTE; if( stat & SSPSR_RNE ) EX_RX_BYTE; } while( nn ); // Вычитывание хвостика FIFO do { if( (stat = SSPSR) & SSPSR_RNE ) EX_RX_BYTE; } while( stat & SSPSR_BSY ); // И возможного последнего байта if( SSPSR & SSPSR_RNE ) EX_RX_BYTE;
// } // LEAVE_CRITICAL(); bprintf_str( "RX:"); for( nn = 0; nn<size; nn++ ) bprintf_str( "%02X ", ex_rx_buf[nn] ); bprintf( "end" ); }
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 3 2006, 07:26
|
Местный
  
Группа: Свой
Сообщений: 366
Регистрация: 5-09-06
Из: Санкт-Петербург
Пользователь №: 20 107

|
Цитата(zltigo @ Oct 2 2006, 21:33)  Простейший вариант без прерывания. На частоте SPI ~7.5MHz и ниже FIFO не успевает опустошаться и SSEL не дергается, как и требовалось. Благодарю примного. это, конечно же работает... с небольщой оговоркой - 1. частота процессора 14.7456МГц (не надо больше и из соображений требований к потреблению тока) 2. За время записи второго байта в фифу (SPI ~ 2МГц) первый успевает из нее вылететь. Поэтому мне видится наиболее подходящим следующий алгоритм: (псевдо) // очистить приемную очередь... потом: SSPDR = *tx_ptr++; tx_cnt--; do { // можно проверить есть ли место в передающей фифе. если нет - подождать. без этого тоже работает SSPDR = *tx_ptr++; *rx_cnt++ = SSPDR; // наверное нужно проверить rxne флаг, но вроде и без этого работает } while(--tx_cnt) ; // и в конце дочистить приемную очередь
|
|
|
|
|
Oct 3 2006, 07:48
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(diwil @ Oct 3 2006, 10:26)  1. частота процессора 14.7456МГц (не надо больше и из соображений требований к потреблению тока) 2. За время записи второго байта в фифу (SPI ~ 2МГц) первый успевает из нее вылететь. 1.Что-то у Вас не то с оптимизаций/компилятором - на частоте процессора в ~15MHz и ~2MHz (точнее где-то 1,84...) SPI контролер успевает загружать FIFO без пауз. Мой пример компилировался IAR, ARM Mode, максимальная оптимизация по скорости. Цитата(diwil @ Oct 3 2006, 10:26)  SSPDR = *tx_ptr++; tx_cnt--;
do { // можно проверить есть ли место в передающей фифе. если нет - подождать. без этого тоже работает SSPDR = *tx_ptr++; *rx_cnt++ = SSPDR; // наверное нужно проверить rxne флаг, но вроде и без этого работает } while(--tx_cnt) ; Это то, что я имел ввиду когда: Цитата байты запихиваются в FIFO и со сдвигом на несколько засунутых в FIFO байт считываются. Но: 2. Если у Вас "успевает вылететь", то этому уже ничем не поможешь в случае если количество за раз передаваемых байт превышает размер FIFO :-(.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 3 2006, 08:06
|
Местный
  
Группа: Свой
Сообщений: 366
Регистрация: 5-09-06
Из: Санкт-Петербург
Пользователь №: 20 107

|
Цитата(zltigo @ Oct 3 2006, 11:48)  Но: 2. Если у Вас "успевает вылететь", то этому уже ничем не поможешь в случае если количество за раз передаваемых байт превышает размер FIFO :-(. это тоже мне странно... похоже скорость доступа к переферии оч маленькая. компилю ГЦЦ - скомпилиный код почти идеальный (я бы так же на ассемблере написал). Дело, наверное, в том, что скорость переферии у меня 14.7456/4 (это экономит миллиамперы). Похоже, что str rX, [rY], где rY ссылается на переферию занимает 2 такта переферии, а не процессора. буду разбираться. пасиб
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|