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

 
 
> Зависает прошивка. Реализовал стек для хранения принятых по USB данных и дальнейшей передачи по SSC., at91sam7s
Bulat
сообщение Apr 29 2010, 05:47
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 206
Регистрация: 12-10-06
Из: ufa
Пользователь №: 21 241



Принима данные из UDP, разбираю FIFO буфер UDP и заполняю собственный стек типа FIFO для SSC. SSC по прерыванию забирает из моего стека данные и отправляет их со скоростью 100 кбит\с. Дополнительный стек необходим, чтобы сильно не тормозить работу компьютера по USB, чтобы не происходила потеря данных.
CODE

unsigned int que[16]; // Стек типа FIFO для передаваемых по SSC данных
unsigned int head = 0; //начальный индекс
unsigned int tail = 0; //конечный индекс

//Обработчик прерывания SSC
__ramfunc void SscHandler()
{
AT91C_BASE_SSC->SSC_THR = que[head]; //отправляем на передачу слово из стека для SSC
head = (head+1)&0xf; //инкрементируем начальный индекс стека
//если начальный индекс обнулился, значит стек пуст и готов для повторного заполнения
if(head == 0) { AT91C_BASE_SSC->SSC_CR = AT91C_SSC_TXDIS ;
AT91C_BASE_SSC->SSC_IDR = 0xfff; jj=0;}
unsigned int dummy = AT91C_BASE_SSC->SSC_SR;
}

void main()
{
while(1)
{
//если FIFO UDP пуст
if(length == 0)
{
// проверка флага прерывания от EP2
if((AT91C_BASE_UDP->UDP_ISR) & AT91C_UDP_EPINT2)
{
if(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_OUT] & pCDC.currentRcvBank)
length = regUDP->UDP_CSR[AT91C_EP_OUT]>>16;
}
}

//если в FIFO UDP присутствуют данные, то заполняем
if(length != 0)
{
if(jj==0) //если стек для SSC не заполнен, то продолжаем его заполнять
{
unsigned int byte[4];
byte[0] = regUDP->UDP_FDR[AT91C_EP_OUT];
byte[1] = regUDP->UDP_FDR[AT91C_EP_OUT];
byte[2] = regUDP->UDP_FDR[AT91C_EP_OUT];
byte[3] = regUDP->UDP_FDR[AT91C_EP_OUT];


unsigned int dat_buf = (byte[3]<<24)|(byte[2]<<16)|(byte[1]<<8)|byte[0];
//формируем 32-битное слово для передачи по SSC

que[tail] = dat_buf;
tail = (tail+1)&0xf;
//инкрементируем конечный индекс и накладываем маску (размер стека 16 слов)
if(tail == 0) jj = 1;
//если конечный индекс обнулился, значит стек полон и необходимо прекратить запись в него, пока он не освободится
else {AT91C_BASE_SSC->SSC_CR = AT91C_SSC_TXEN; AT91C_BASE_SSC->SSC_IER = AT91C_SSC_TXRDY;}
//иначе разрешаем передачу по SSC

length = length-4; //уменьшаем значение остатка в FIFO UDP

}//if(jj == 0)

if(length == 0)
{
Udp_ep_clr_flag(regUDP,AT91C_EP_OUT, pCDC.currentRcvBank);
if(pCDC.currentRcvBank == AT91C_UDP_RX_DATA_BK0)pCDC.currentRcvBank = AT91C_UDP_RX_DATA_BK1;
else pCDC.currentRcvBank = AT91C_UDP_RX_DATA_BK0;
AT91C_BASE_UDP->UDP_ICR = 0xFFFFFFFF;
}

}//if(length != 0)

}//while(1)
}//main


Таким образом, в случае заполнения стека que[], данные из FIFO UDP не считываются пока SSC не опустошит свой стек que[].
Если убрать из обработчика SSC останов передатчика (AT91C_BASE_SSC->SSC_CR = AT91C_SSC_TXDIS ; AT91C_BASE_SSC->SSC_IDR = 0xfff;) то прошивка не повисает. Но тогда данные, передаваемые по SSC будут уже не те. Не понятно где может повиснуть прошивка, так как останов и повторный запуск SSC работает, проблемы возникли, когда я ввел стек.

Сообщение отредактировал rezident - Apr 30 2010, 21:11
Причина редактирования: Редактирование оформления цитаты исходника.
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
Bulat
сообщение Apr 29 2010, 09:24
Сообщение #2


Местный
***

Группа: Участник
Сообщений: 206
Регистрация: 12-10-06
Из: ufa
Пользователь №: 21 241



Цитата(aaarrr @ Apr 29 2010, 12:21) *
Это как раз понятно - зависнет как миленький, если в прерывании UDP "стек" будет заполнен полностью при запрещенных прерываниях SSC.
Сделайте для начала нормальное FIFO.

я могу не запрещать прерывания SSC, а просто его останавливать, также зависать будет. И потом прерывания от EP2 UDP у меня запрещены. Я в главном цикле просто флаг опрашиваю.
Вы имеете в виду мой стек que[] неправильно реализован? Он вроде проще некуда реализован. Проверял, принцип FIFO выполняется, индексы автоматически обнуляются, т.е. работает по кольцу. А что именно в моем стеке не так?
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Apr 29 2010, 09:33
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(Bulat @ Apr 29 2010, 13:24) *
я могу не запрещать прерывания SSC, а просто его останавливать, также зависать будет.

Какая разница, если все равно некому будет разрешить?

Цитата(Bulat @ Apr 29 2010, 13:24) *
И потом прерывания от EP2 UDP у меня запрещены. Я в главном цикле просто флаг опрашиваю.

И это не важно.

Цитата(Bulat @ Apr 29 2010, 13:24) *
А что именно в моем стеке не так?

У нормального кольцевого буфера нет начала и конца. Степень заполнения определяется по разности указателей (при этом одна ячейка буфера теряется), или по отдельной переменной.
Go to the top of the page
 
+Quote Post
Bulat
сообщение Apr 29 2010, 10:25
Сообщение #4


Местный
***

Группа: Участник
Сообщений: 206
Регистрация: 12-10-06
Из: ufa
Пользователь №: 21 241



Цитата(aaarrr @ Apr 29 2010, 15:33) *
Какая разница, если все равно некому будет разрешить?


И это не важно.


У нормального кольцевого буфера нет начала и конца. Степень заполнения определяется по разности указателей (при этом одна ячейка буфера теряется), или по отдельной переменной.

так меня же не кольцевой буфер интересует, а просто буфер FIFO, то есть мне не нужно сохранять считанное из буфера значение, пускай оно затирается. А в обычном буфере FIFO только по обнулению индекса головы и хвоста можно определить заполнен или пуст буфер, соответственно. За основу моего буфера я взял следующий класс:
Код
class queue
{
private:
  int head, tail; // индексы головы и хвоста очереди
  int q[16]; // î÷åðåäü ñîäåðæàùàÿ äåñÿòü ýëåìåíòîâ

public:
  queue() : head(0),tail(0)
  {}
  int enqueue(int number) // запись в очередь
  {
  q[tail] = number;
  tail = (tail+1)&0xf;
  return tail;
  }
  int dequeue () // извлечение из очереди
  {
  int temp = q[head];
  head = (head+1) &0xf;
  return temp;
  }
};
Соответственно, если tail==0 - очередь заполнена, если head == 0, очередь пустая.

В данном случае разве такой алгоритм не подходит?
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Apr 29 2010, 10:34
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(Bulat @ Apr 29 2010, 14:25) *
В данном случае разве такой алгоритм не подходит?

Он подходит, если работать в режиме: приняли 16 слов из UDP -> разрешили SSC, отправили 16 слов, запретили SSC -> приняли 16 слов из UDP...
А так как SSC лопатит постоянно, то все и ломается, ибо это:
Код
if(tail == 0) jj = 1; //если конечный индекс обнулился, значит стек полон и необходимо прекратить запись в него, пока он не освободится

неверно, буфер может быть в этот момент и пуст.
Go to the top of the page
 
+Quote Post
Bulat
сообщение Apr 30 2010, 09:47
Сообщение #6


Местный
***

Группа: Участник
Сообщений: 206
Регистрация: 12-10-06
Из: ufa
Пользователь №: 21 241



Цитата(aaarrr @ Apr 29 2010, 16:34) *
Он подходит, если работать в режиме: приняли 16 слов из UDP -> разрешили SSC, отправили 16 слов, запретили SSC -> приняли 16 слов из UDP...
А так как SSC лопатит постоянно, то все и ломается, ибо это:
Код
if(tail == 0) jj = 1; //если конечный индекс обнулился, значит стек полон и необходимо прекратить запись в него, пока он не освободится

неверно, буфер может быть в этот момент и пуст.

Вот код с кольцевой очередью
CODE

const int qsize = 100;
unsigned int que[qsize]; // Стек типа FIFO для передаваемых по SSC данных
unsigned int head = 1; //начальный индекс
unsigned int tail = 1; //конечный индекс

//Обработчик прерывания SSC
__ramfunc void SscHandler()
{
if(head == tail) { AT91C_BASE_SSC->SSC_CR = AT91C_SSC_TXDIS ; jj=0;}
else
{
AT91C_BASE_SSC->SSC_THR = que[head];
head = head%qsize+1;
}
unsigned int dummy = AT91C_BASE_SSC->SSC_SR;
}

void main()
{
ii=1; //флаг разрешающий запускать SSC
while(1)
{
//если FIFO UDP пуст
if(length == 0)
{
// проверка флага прерывания от EP2
if((AT91C_BASE_UDP->UDP_ISR) & AT91C_UDP_EPINT2)
{
if(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_OUT] & pCDC.currentRcvBank)
length = regUDP->UDP_CSR[AT91C_EP_OUT]>>16;
}
}

//если в FIFO UDP присутствуют данные, то заполняем
if(length != 0)
{
if(jj==0) //если стек для SSC не заполнен, то продолжаем его заполнять
{
unsigned int byte[4];
byte[0] = regUDP->UDP_FDR[AT91C_EP_OUT];
byte[1] = regUDP->UDP_FDR[AT91C_EP_OUT];
byte[2] = regUDP->UDP_FDR[AT91C_EP_OUT];
byte[3] = regUDP->UDP_FDR[AT91C_EP_OUT];

//формируем 32-битное слово для передачи по SSC
unsigned int dat_buf = (byte[3]<<24)|(byte[2]<<16)|(byte[1]<<8)|byte[0];

if(tail%qsize+1 == head) { jj = 1; ii = 1;} //прекращаем считывать из FIFO UDP
else
{
que[tail] = dat_buf;
tail = tail%qsize+1;

if(ii==1){AT91C_BASE_SSC->SSC_CR = AT91C_SSC_TXEN; ii=0;}
}

length = length-4; //уменьшаем значение остатка в FIFO UDP

}//if(jj == 0)

if(length == 0)
{
Udp_ep_clr_flag(regUDP,AT91C_EP_OUT, pCDC.currentRcvBank);
if(pCDC.currentRcvBank == AT91C_UDP_RX_DATA_BK0)
pCDC.currentRcvBank = AT91C_UDP_RX_DATA_BK1;
else
pCDC.currentRcvBank = AT91C_UDP_RX_DATA_BK0;
AT91C_BASE_UDP->UDP_ICR = 0xFFFFFFFF;
}

}//if(length != 0)

}//while(1)
}//main


Теперь запись идет по кольцу. (Алгоритм кольцевой очереди проверил в консольном приложении. )
Сейчас передача вообще не запускается. Почему в моей программе очередь не работает?

Модератор (rezident). Уважаемый пользователь Bulat, потрудитесь-ка сами с редактированием оформления цитат исходников до их публикации. Так, чтобы они (цитаты) не "распирали" страницу.

Сообщение отредактировал rezident - May 9 2010, 00:08
Причина редактирования: Правка оформления цитаты исходника.
Go to the top of the page
 
+Quote Post



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

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 18:00
Рейтинг@Mail.ru


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