|
Не кооректный старт программы |
|
|
|
May 21 2009, 14:36
|

пуля
   
Группа: Свой
Сообщений: 674
Регистрация: 10-05-06
Из: Уфа
Пользователь №: 16 959

|
Написал программу, заливаю, включаю, неработает. Начинает работать только после внешнего ресета. Код: CODE u8 buf[3801]; u8 crc8_crn = 0; // CRC8 для текущей команды u8 crc8_prev = 0; // CRC8 для предыдущей команды u8 crc8 = 0xFF; // CRC8 для подсчета, используется как буфер u8 comand_crn[5] = {0,0,0,0,0}; // Запрос текущий u8 comand_prev[5] = {0,0,0,0,0}; // Запрос предыдущий
u8 crc8_array[256] = {...};
void ReadADC(void); // тение данных с АЦП u8 ReadWriteSPI1(u8 data); // Чтение и запись с SPI1 u8 CalcCOMAND_CRC8(u8 col); // Расчет CRC8 приходящей команды u8 crc8_table(u8 data); // Расчет CRC8 по таблице void CalcBUF_CRC8(void); // Расчет CRC8 у buf[] и запись в последний номер crc8
int main (void){ // System initialization, this will map the exception vectors. SystemInit(APBDIVISOR); // initialization PLL PLLInit(); // Power Control PowerControl();
// First disable interrupts. __disable_interrupt();
// Setup interrupt controller. InitVIC(); InitTimer0Interrupt(Timer0Beat); // Periodic timer initialization. InitTimer0(); // Enable interrupts. __enable_interrupt();
// Start periodic timer. // StartTimer0();
// Set up peripheral registers. InitGPIO(); InitSPI1(); u8 i = 0; u8 fg; crc8_prev = 0; for (;;){ // Loop forever.
fg = ReadWriteSPI1(0); if (fg != 0) { comand_crn[0] = fg; S1SPDR = 0; i = 1; while (SPI1_SSEL == 0){ if ((S1SPSR & 0x80)) { comand_crn[i++] = S1SPDR; S1SPDR = 0; } }// end While
// Проверка CRC8 приходящего запроса crc8 = 0xFF; crc8_crn = CalcCOMAND_CRC8(i-1);// щас фиксированно 3 байта приходит
if (crc8_prev == 0) { //==================================================== // Сначала отвечаем на запрос (предыдущий) for (u16 k = 0; k <=3800; k++) {ReadWriteSPI1(buf[k]);}; //==================================================== // Затем выполняем команду switch (comand_crn[0]){ // В зависимости какая команда пришла //---------------------------------------------------- case 'k' : //0x6B = 107 // Команда "" ..... break; //---------------------------------------------------- case 'z' : //'z' = 122 = 0x7A - Команда "Тест памяти" ..... break; //---------------------------------------------------- case 0xA0 : //'' 160 = - Команда "" ..... break; //---------------------------------------------------- default: { .... } //---------------------------------------------------- }// Конец swith crc8_prev = crc8_crn; for (u8 ct = 0; ct <= 4; ct++) {comand_prev[ct] = comand_crn[ct];}; } //else { S1SPDR = 0;} }// Есть ли команда }// For - LOOP }// End Main
u8 ReadWriteSPI1(u8 data){ S1SPDR = data; while (!(S1SPSR & 0x80)); return S1SPDR; };
u8 crc8_table(u8 data){ crc8 = crc8_array[(data ^ crc8)&0xff]; return crc8; }
u8 CalcCOMAND_CRC8(u8 col){ crc8 = 0xFF; for (u8 n = 0; n <= 2; n++) { crc8 = crc8_array[((comand_crn[n])^ crc8)&0xff]; } return crc8; }
void CalcBUF_CRC8(void){ crc8 = 0xFF; for (u16 n = 0; n <= 3799; n++) { crc8 = crc8_table(buf[n]); } buf[3800] = crc8; } Так вот crc8 в строке Код // Проверка CRC8 приходящего запроса crc8 = 0xFF; crc8_crn = CalcCOMAND_CRC8(i-1);// щас фиксированно 3 байта приходит проверятеся и не равен нулю. Хотя приходит коректное... Проверял ... Если нажать на кнопку сброса - то всё окей! (!) Затык получается в "if (crc8_prev == 0)" , хотя при 2-3 приходе команды crc ведь должен нормальным быть... Инициализация мк проходит - это точно. Стоит супервизор. МК LPC2194 /01. Среда IAR, оптимизация High, ставил none - не помогает. Что может быть? почему после ресета начинает нормально работать??? Заранее большое спасибо!
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 14)
|
May 21 2009, 16:45
|

пуля
   
Группа: Свой
Сообщений: 674
Регистрация: 10-05-06
Из: Уфа
Пользователь №: 16 959

|
Цитата Инициализация железа в main - дурной тон. В startup'e для этого вызывается low_level_init. Если я не ошибаюсь, по крайней мере поиск в хелпах ИАРа не дал результатов, то стартап это из Кейла? Ну а насчет прерываний... я попробую. Но имхо дело в другом... в чем сам не пойму, либо с памятью что-то при инициализации. Забыл сказать, что напряжение питания нарастает очень медленно. Выкручивается переменником с внешнего источника... с маленькой скоростью. Поэтому стоит монитор питания. 240 мс ресетит.
|
|
|
|
|
May 22 2009, 05:38
|

пуля
   
Группа: Свой
Сообщений: 674
Регистрация: 10-05-06
Из: Уфа
Пользователь №: 16 959

|
Немного подправил код... Код for (;;){ // Loop forever. fg = ReadWriteSPI1(0); if (fg != 0) { comand_crn[0] = fg; S1SPDR = crc8; // Чтоб видно было что crc8 нулевое или нет.... i = 1; while (SPI1_SSEL == 0){ if ((S1SPSR & 0x80)) { comand_crn[i++] = S1SPDR; S1SPDR = 0; } }// end While // if (crc8 == 0) - нет проверки crc8 { //==================================================== // Сначала отвечаем на запрос (предыдущий) for (u16 k = 0; k <=3800; k++) {ReadWriteSPI1(0xF0/*buf[k]*/);}; //==================================================== И угадайте что передаёт.. либо 0x0F, либо 0x87 = 10000111 или даже 0011 1100 т.е. все но не 11110000. Инициализация SPI: Код void InitSPI1() { PINSEL1 |= 0x2A8; /* S1SPCR_bit.BITENABLE = 0; // BITENABLE = 0 Передача и прием 8 бит.. S1SPCR_bit.CPHA = 0; // CPHA = 0 (фаза синхроимпульса - выборка по фронту SCK) S1SPCR_bit.CPOL = 0; // CPOL = 0 (SCK имеет Активный Высокий уровень) S1SPCR_bit.MSTR = 0; // MSTR = 0 Режим SPI Slave (подчиненный) S1SPCR_bit.LSBF = 0; // LSBF = 0 Первый бит старший S1SPCR_bit.SPIE = 0; // SPIE = 0 Прерывания от SPI1 запрещены. */ S1SPCR = 0; S1SPDR = 0; } Чтение и запись SPI: Код u8 ReadWriteSPI1(u8 data){ S1SPDR = data; while (!(S1SPSR & 0x80)); return S1SPDR; }; Почему не корректно работает SPI? Где-то ошибка?
|
|
|
|
|
May 22 2009, 08:22
|

пуля
   
Группа: Свой
Сообщений: 674
Регистрация: 10-05-06
Из: Уфа
Пользователь №: 16 959

|
Проанализировав результаты, посоветовавщись со старшими товарищами, пришел в выводу, что сбивается синхронизация... т.е. чтение 1 байта начинается не с самого начала, а где-то с последующего бита. т.е. код выглядит так, если раскрыть функцию: Код S1SPDR = 0; while (!(S1SPSR & 0x80)); fg = S1SPDR; if (fg != 0) { comand_crn[0] = fg; И похоже в этом куске сбой синхронизации...
|
|
|
|
|
May 22 2009, 09:05
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(bullit @ May 22 2009, 11:22)  Проанализировав результаты, посоветовавщись со старшими товарищами, пришел в выводу, что сбивается синхронизация... Синхронизация должна быть внешней. То есть Master должен дёргать ногу SlaveSelect перед началом передачи. Если такой возможности нет, то надо осуществить синхронизацию программно. Так я в одном проекте в слэйв предварительно записываю 0x01. Master в начале передаёт нули, проверяя полученный байт. Увидев рассинхронизацию, определяет её по положению 1 и устраняет программно передав необходимое число стробов. После этого начинает передачу пакета.
|
|
|
|
|
May 22 2009, 11:32
|

пуля
   
Группа: Свой
Сообщений: 674
Регистрация: 10-05-06
Из: Уфа
Пользователь №: 16 959

|
Моё устройство работает по запросу (мое устройство слейв). Т.е. от стороннего устройства приходит запрос от 3 до 5(8) байт, я же в ответ должен передать 3801 байт (данные АЦП). Но отвечаю я не на поступивший в данный момент запрос, а на предыдущий. Сделано с целью чтоб небыло задержек между запросом и ответом. Так как формирование 3801 байт займет неопределенное количество времени. Принцип работы моего устройства таков: 1) пришел запрос (все 3-5 байт) 1.1 мастер держит некоторое время SSEL в неактивном уровне 2) отправляю сформированный буфер из 3801 байта 3) проверяю равен ли crc8 нулю, предыдущего запроса 4) равен нулю, тогда: по первому биту запроса я определяю (swith(comanda[0])) "чего хочет" мастер и перехожу на нужный обработчик команды. Остальные байты являются параметрами. Там же формирую ответный буфер. 5) если не равен нулю crc8 : заполняю буфер нулями 6) считаю(проверка наверху) crc8 последнего запроса На рисунке представленна осцилограмма, как должно быть. Верхний - клок. Желтый запрос от мастера. Синий - мой ответ 38001 байт. Серый (который уровнем 1.6 вольт (хотя равен естесно 3.3 - это из памяти)) - SSEL. Получается полудуплекс. Вот как "нормально принять" данные с SPI? - стоит сейчас задача. Вот примерно так. Скорость SPI может быть не выше 2 МГц, сейчас 800кило. Период опроса не менее 100 мс. Что-то нужно еще? добавлю Сейчас есть возможность загнать чипселект мастера на ЕИНТ0.
Эскизы прикрепленных изображений
|
|
|
|
|
May 22 2009, 11:46
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(bullit @ May 22 2009, 14:32)  Что-то нужно еще? добавлю Практически достаточно.  Осталось только 2 вопроса. 1) В каком месте диаграмы происходит сбой? 2) Есть ли возможность/желание подправить мастер? Обычно я делаю несколько по другому. CRC считаю во время получения пакета. В случае ошибки CRC выдаю запрос на повтор. Это, естественно, можно сделать и на предыдущий, хотя тут вопрос конечно. При рассинхронизации одного пакета - не страшно как я понимаю? Идёт повторный запрос - Вы его обрабатываете и выдаёте. В чём проблема? Или Вы просто пытаетесь выяснить почему это происходит? Если дело в нарастании питания, то попробуйте сделать значительную задержку перед инициализацией оборудования. Главное, чтобы у вас всё работало даже при порче/пропадании пакетов.
|
|
|
|
|
May 22 2009, 12:04
|

пуля
   
Группа: Свой
Сообщений: 674
Регистрация: 10-05-06
Из: Уфа
Пользователь №: 16 959

|
1) сбой как я понимаю появляется уже на приеме. потому как выводил crc8 1-ым битом при запросе, он небыл равен нулю (и прошу заметить - не был постоянным). И естественно после проверки CRC, та часть программы которая формирует ответ? не выполнялась. 2) есть, но в ограничено. Смотря что и как.
Дело в том что после пуска устройств, придёт хоть 100 запросов, устройство не получает правильный результат. ПОКА не нажмешь кнопку сброса. Именно ответ описанный в моем посте 5 подвел меня к выводу что имеет место рассинхронизация. Одним словом не правильная работа SPI.
ИМХО отсутствие в интерфейсе SPI флага - SSEL - большой недостаток. так бы я поставил прерывание на изменение или переход в активный режим. В процессе приема от мастера байт, просто следил бы, SSEL еще в активном уровне? и небыло бы проблем, а тут... Проще на прерывание поставить чипселект, и смотреть первый бит равен нулю? Но тут опять вылезают всякие козебяки: а если параметр-байт равне нулю? и это не последний параметр? и сколько ждать мне? все 5, а если максимум возможно 8? - это трабла. Отсутствие флага что чипселект активен - не есть гут!
|
|
|
|
|
May 23 2009, 10:57
|

пуля
   
Группа: Свой
Сообщений: 674
Регистрация: 10-05-06
Из: Уфа
Пользователь №: 16 959

|
Рещил на Чипселект поставить прерывание по спаду. Код инициализации вывода Р0.16 как eint0: Код PINSEL1 |= 1; // Вывод как EINT0 EXTMODE = 1; // Срабатывание на перепад EXTPOLAR = 0; // На отрицательный перепад Код инициализации прерывания: Код void InitEINT0Interrupt() { VICIntSelect &= ~VIC_EINT0_bit; VICVectAddr0 = (unsigned int)&EINT0Interrupt; VICVectCntl0 = 0x20 | VIC_EINT0; // Enable vector interruзе VICIntEnable = VIC_EINT0_bit; // Enable interrupt. } Обработчик: Код __irq __arm void EINT0Interrupt(void) { VICIntEnClear = 0x00004000; // Disable EINT0 in the VIC u8 fg; countercom = 0; EXTINT = 1; // Сбросить флаг внешного прерывание EINT0 while (!(S1SPSR & 0x80)) { }; fg = S1SPDR; if (fg != 0) { countercom++; comand_crn[countercom] = fg; S1SPDR = 0; } else {S1SPDR = 0;} EXTINT = 0x01; // Clear the peripheral interrupt flag VICIntEnable = 0x00004000; // Enable EINT0 in the VIC VICVectAddr = 0; // reset VIC } Но почему-то прерывание не срабатывает. Отладчиком смотрю, в регистре VICIRQStatus 14(eint0) установлен. Что не так?
|
|
|
|
|
May 23 2009, 14:44
|

пуля
   
Группа: Свой
Сообщений: 674
Регистрация: 10-05-06
Из: Уфа
Пользователь №: 16 959

|
Решил пока не заморачиваться с прерыванием... Написал маленькую программу которая проверят поступивший байт: Код for (;;){ // Loop forever. while (!(FIO0PIN & 0x10000)){ // пока чипселект в активном уровне while (!(S1SPSR & 0x80)){}; // ждем флага о получении байта if (S1SPDR != 0xAA) {нога в верх} else {нога вниз} }// end While нога вниз; } Вот при старте работает не корректно.... Поразмыслив пришел к следующему, что причины могут быть следующими: 1) плавный рост напряжение, и его "плавучесть" во время набора 2) "ранний" старт, т.е. монитор питания срабатывает слишком рано 3) программа, что очень маловероятно. Есть вариант поставить таймер при старте, и пусть сам себя отключает через ~10 сек..
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|