|
Зависает прошивка. Реализовал стек для хранения принятых по USB данных и дальнейшей передачи по SSC., at91sam7s |
|
|
|
Apr 29 2010, 05:47
|
Местный
  
Группа: Участник
Сообщений: 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
Причина редактирования: Редактирование оформления цитаты исходника.
|
|
|
|
|
 |
Ответов
|
Apr 29 2010, 09:24
|
Местный
  
Группа: Участник
Сообщений: 206
Регистрация: 12-10-06
Из: ufa
Пользователь №: 21 241

|
Цитата(aaarrr @ Apr 29 2010, 12:21)  Это как раз понятно - зависнет как миленький, если в прерывании UDP "стек" будет заполнен полностью при запрещенных прерываниях SSC. Сделайте для начала нормальное FIFO. я могу не запрещать прерывания SSC, а просто его останавливать, также зависать будет. И потом прерывания от EP2 UDP у меня запрещены. Я в главном цикле просто флаг опрашиваю. Вы имеете в виду мой стек que[] неправильно реализован? Он вроде проще некуда реализован. Проверял, принцип FIFO выполняется, индексы автоматически обнуляются, т.е. работает по кольцу. А что именно в моем стеке не так?
|
|
|
|
|
Apr 29 2010, 09:33
|
Гуру
     
Группа: Свой
Сообщений: 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)  А что именно в моем стеке не так? У нормального кольцевого буфера нет начала и конца. Степень заполнения определяется по разности указателей (при этом одна ячейка буфера теряется), или по отдельной переменной.
|
|
|
|
|
Apr 29 2010, 10:25
|
Местный
  
Группа: Участник
Сообщений: 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, очередь пустая. В данном случае разве такой алгоритм не подходит?
|
|
|
|
|
Apr 29 2010, 10:34
|
Гуру
     
Группа: Свой
Сообщений: 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; //если конечный индекс обнулился, значит стек полон и необходимо прекратить запись в него, пока он не освободится неверно, буфер может быть в этот момент и пуст.
|
|
|
|
|
Apr 30 2010, 09:47
|
Местный
  
Группа: Участник
Сообщений: 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
Причина редактирования: Правка оформления цитаты исходника.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|