реклама на сайте
подробности

 
 
> Не кооректный старт программы
bullit
сообщение May 21 2009, 14:36
Сообщение #1


пуля
****

Группа: Свой
Сообщений: 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 - не помогает.
Что может быть? почему после ресета начинает нормально работать???
Заранее большое спасибо!
Go to the top of the page
 
+Quote Post
2 страниц V   1 2 >  
Start new topic
Ответов (1 - 14)
sergeeff
сообщение May 21 2009, 16:18
Сообщение #2


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Железо лучше инициализировать при запрещенных прерываниях, и разрешать прерывания потом.

Инициализация железа в main - дурной тон. В startup'e для этого вызывается low_level_init.
Go to the top of the page
 
+Quote Post
bullit
сообщение May 21 2009, 16:45
Сообщение #3


пуля
****

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



Цитата
Инициализация железа в main - дурной тон. В startup'e для этого вызывается low_level_init.

Если я не ошибаюсь, по крайней мере поиск в хелпах ИАРа не дал результатов, то стартап это из Кейла?
Ну а насчет прерываний... я попробую.
Но имхо дело в другом... в чем сам не пойму, либо с памятью что-то при инициализации.
Забыл сказать, что напряжение питания нарастает очень медленно. Выкручивается переменником с внешнего источника... с маленькой скоростью. Поэтому стоит монитор питания. 240 мс ресетит.
Go to the top of the page
 
+Quote Post
DpInRock
сообщение May 21 2009, 19:10
Сообщение #4


Гуру
******

Группа: Участник
Сообщений: 2 254
Регистрация: 4-05-07
Из: Moscow
Пользователь №: 27 515



Казалось бы, чего проще.
Убираем из программы всё. Потом грузим. Добавляя понемногу.И находим ответ.


--------------------
On the road again (Canned Heat)
Go to the top of the page
 
+Quote Post
bullit
сообщение May 22 2009, 05:38
Сообщение #5


пуля
****

Группа: Свой
Сообщений: 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? Где-то ошибка?
Go to the top of the page
 
+Quote Post
bullit
сообщение May 22 2009, 08:22
Сообщение #6


пуля
****

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



Проанализировав результаты, посоветовавщись со старшими товарищами, пришел в выводу, что сбивается синхронизация...
т.е. чтение 1 байта начинается не с самого начала, а где-то с последующего бита.
т.е. код выглядит так, если раскрыть функцию:
Код
S1SPDR = 0;
  while (!(S1SPSR & 0x80));
  fg = S1SPDR;
    if (fg != 0) {
      comand_crn[0] = fg;

И похоже в этом куске сбой синхронизации...
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение May 22 2009, 09:05
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(bullit @ May 22 2009, 11:22) *
Проанализировав результаты, посоветовавщись со старшими товарищами, пришел в выводу, что сбивается синхронизация...

Синхронизация должна быть внешней.

То есть Master должен дёргать ногу SlaveSelect перед началом передачи.

Если такой возможности нет, то надо осуществить синхронизацию программно.
Так я в одном проекте в слэйв предварительно записываю 0x01.
Master в начале передаёт нули, проверяя полученный байт. Увидев рассинхронизацию, определяет её по положению 1 и устраняет программно передав необходимое число стробов.

После этого начинает передачу пакета.
Go to the top of the page
 
+Quote Post
bullit
сообщение May 22 2009, 09:25
Сообщение #8


пуля
****

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



А пример реализации интерфейса SPI не покажите?
У меня приходит от 3 до 5 байт, выходит (только после приема) 3800 байт. Между передачей и приёмом SSEL переходит в неактивный уровень.

Мне так кажется что проще загнать в прерывание SPI. Создать параметр что данные пришли , т.е. прерывание сработало именно при запросе, а не при ответе. И поехали...
а в майне в вайл вставить опрос параметра , что данные(запрос) получены.
Так будет лучшим вариантом?

SSEL можно завести на SPI, сейчас стоит на соседней ножке. SSEL к подтянут к активному (т.е. "0") уровню.
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение May 22 2009, 11:10
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Честно говоря не совсем понял Ваши предложения/вопрос.

Работа с SPI по прерываниям - на мой взгляд - чушь. При скорости SPI в 60/8 = 7.5МГц время приёма/передачи байта составит 1мкс. Вызывать прерывания каждую мкс при медлительном обработчике прерываний - это замедлит и ухудшит работу всего устр-ва. С другой стороны - убей-непонимаю как это может помочь синхронизации.

Для того, чтобы Вам смогли помочь опишите хотябы структуру устр-ва. Что с чем общается по SPI и зачем они это делают. А то вообще ничего не понятно.
Go to the top of the page
 
+Quote Post
bullit
сообщение May 22 2009, 11:32
Сообщение #10


пуля
****

Группа: Свой
Сообщений: 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.
Эскизы прикрепленных изображений
Прикрепленное изображение
 
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение May 22 2009, 11:46
Сообщение #11


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(bullit @ May 22 2009, 14:32) *
Что-то нужно еще? добавлю


Практически достаточно. smile.gif

Осталось только 2 вопроса.
1) В каком месте диаграмы происходит сбой?
2) Есть ли возможность/желание подправить мастер?

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

При рассинхронизации одного пакета - не страшно как я понимаю? Идёт повторный запрос - Вы его обрабатываете и выдаёте. В чём проблема? Или Вы просто пытаетесь выяснить почему это происходит?

Если дело в нарастании питания, то попробуйте сделать значительную задержку перед инициализацией оборудования. Главное, чтобы у вас всё работало даже при порче/пропадании пакетов.
Go to the top of the page
 
+Quote Post
bullit
сообщение May 22 2009, 12:04
Сообщение #12


пуля
****

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



1) сбой как я понимаю появляется уже на приеме. потому как выводил crc8 1-ым битом при запросе, он небыл равен нулю (и прошу заметить - не был постоянным). И естественно после проверки CRC, та часть программы которая формирует ответ? не выполнялась.
2) есть, но в ограничено. Смотря что и как.

Дело в том что после пуска устройств, придёт хоть 100 запросов, устройство не получает правильный результат. ПОКА не нажмешь кнопку сброса.
Именно ответ описанный в моем посте 5 подвел меня к выводу что имеет место рассинхронизация. Одним словом не правильная работа SPI.

ИМХО отсутствие в интерфейсе SPI флага - SSEL - большой недостаток. так бы я поставил прерывание на изменение или переход в активный режим. В процессе приема от мастера байт, просто следил бы, SSEL еще в активном уровне? и небыло бы проблем, а тут...
Проще на прерывание поставить чипселект, и смотреть первый бит равен нулю? Но тут опять вылезают всякие козебяки: а если параметр-байт равне нулю? и это не последний параметр? и сколько ждать мне? все 5, а если максимум возможно 8? - это трабла. Отсутствие флага что чипселект активен - не есть гут!
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение May 22 2009, 13:05
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Предлогаю простую проверку.
Вы в слэёве при приёме байта (пакета) передаёте 1.
И смотрите что принял мастер.
Если значение отлично от 1, то значит действительно рассинхронизация приёма. Думаем дальше.

Нет необходтмости синхронизироваться по SS. Обычно передают метку начала пакета. Она уникальна и не встречается в данных.
Это определяется протоколом.
Go to the top of the page
 
+Quote Post
bullit
сообщение May 23 2009, 10:57
Сообщение #14


пуля
****

Группа: Свой
Сообщений: 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) установлен.
Что не так?
Go to the top of the page
 
+Quote Post
bullit
сообщение May 23 2009, 14:44
Сообщение #15


пуля
****

Группа: Свой
Сообщений: 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 сек..
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 29th June 2025 - 17:51
Рейтинг@Mail.ru


Страница сгенерированна за 0.01645 секунд с 7
ELECTRONIX ©2004-2016