|
|
  |
Зависает прошивка. Реализовал стек для хранения принятых по 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
Причина редактирования: Правка оформления цитаты исходника.
|
|
|
|
|
May 8 2010, 09:41
|

Гуру
     
Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514

|
Посмотрите, как реализуется кольцевой буфер на примере serial.c от Keil Код /******************************************************************************/ /* */ /* SERIAL.C: Interrupt Controlled Serial Interface for RTX-51 tiny */ /* */ /******************************************************************************/
#include <REG932.H> /* special function register 8052 */ #include <rtx51tny.h> /* RTX-51 tiny functions & defines */
#define OLEN 8 /* size of serial transmission buffer */ unsigned char ostart; /* transmission buffer start index */ unsigned char oend; /* transmission buffer end index */ idata char outbuf[OLEN]; /* storage for transmission buffer */ unsigned char otask = 0xff; /* task number of output task */
#define ILEN 8 /* size of serial receiving buffer */ unsigned char istart; /* receiving buffer start index */ unsigned char iend; /* receiving buffer end index */ idata char inbuf[ILEN]; /* storage for receiving buffer */ unsigned char itask = 0xff; /* task number of output task */
#define CTRL_Q 0x11 /* Control+Q character code */ #define CTRL_S 0x13 /* Control+S character code */
static bit sendfull; /* flag: marks transmit buffer full */ static bit sendactive; /* flag: marks transmitter active */ static bit sendstop; /* flag: marks XOFF character */
/******************************************************************************/ /* putbuf: write a character to SBUF or transmission buffer */ /******************************************************************************/ static void putbuf (char c) { if (!sendfull) { /* transmit only if buffer not full */ ES = 0; /* disable serial interrupt */ if (!sendactive && !sendstop) { /* if transmitter not active: */ sendactive = 1; /* transfer the first character direct */ SBUF = c; /* to SBUF to start transmission */ } else { /* otherwize: */ outbuf[oend++ & (OLEN-1)] = c; /* transfer char to transmission buffer */ if (((oend ^ ostart) & (OLEN-1)) == 0) sendfull = 1; } /* set flag if buffer is full */ ES = 1; /* enable serial interrupt */ } }
/******************************************************************************/ /* putchar: interrupt controlled putchar function */ /******************************************************************************/ char putchar (char c) { if (c == '\n') { /* expand new line character: */ while (sendfull) { /* wait for transmission buffer empty */ otask = os_running_task_id (); /* set output task number */ os_wait (K_SIG, 0, 0); /* RTX-51 call: wait for signal */ otask = 0xff; /* clear output task number */ } putbuf (0x0D); /* send CR before LF for <new line> */ } while (sendfull) { /* wait for transmission buffer empty */ otask = os_running_task_id (); /* set output task number */ os_wait (K_SIG, 0, 0); /* RTX-51 call: wait for signal */ otask = 0xff; /* clear output task number */ } putbuf (c); /* send character */ return (c); /* return character: ANSI requirement */ }
/******************************************************************************/ /* _getkey: interrupt controlled _getkey */ /******************************************************************************/ char _getkey (void) { while (iend == istart) { itask = os_running_task_id (); /* set input task number */ os_wait (K_SIG, 0, 0); /* RTX-51 call: wait for signal */ itask = 0xff; /* clear input task number */ } return (inbuf[istart++ & (ILEN-1)]); }
/******************************************************************************/ /* serial: serial receiver / transmitter interrupt */ /******************************************************************************/ void serial (void) interrupt 4 using 2 { /* use registerbank 2 for interrupt */ unsigned char c; bit start_trans = 0;
if (RI) { /* if receiver interrupt */ c = SBUF; /* read character */ RI = 0; /* clear interrupt request flag */ switch (c) { /* process character */ case CTRL_S: sendstop = 1; /* if Control+S stop transmission */ break;
case CTRL_Q: start_trans = sendstop; /* if Control+Q start transmission */ sendstop = 0; break;
default: /* read all other characters into inbuf */ if (istart + ILEN != iend) { inbuf[iend++ & (ILEN-1)] = c; } /* if task waiting: signal ready */ if (itask != 0xFF) isr_send_signal (itask); break; } }
if (TI || start_trans) { /* if transmitter interrupt */ TI = 0; /* clear interrupt request flag */ if (ostart != oend) { /* if characters in buffer and */ if (!sendstop) { /* if not Control+S received */ SBUF = outbuf[ostart++ & (OLEN-1)]; /* transmit character */ sendfull = 0; /* clear 'sendfull' flag */ /* if task waiting: signal ready */ if (otask != 0xFF) isr_send_signal (otask); } } else sendactive = 0; /* if all transmitted clear 'sendactive' */ }
}
/******************************************************************************/ /* serial_init: initialize serial interface */ /******************************************************************************/ void serial_init (void) { P1M1 = 0xFE; // Configure P1.0 (TxD) as Output
SCON = 0x52; /* initialize UART */ BRGR0 = 0xF0; /* 9600 baud, 8 bit, no parity, 1 stop bit */ BRGR1 = 0x02; BRGCON = 0x03; } там все применительно под RTX-51, но переделать куски с вызовами функций ОС труда не составляет, главное - сама идея размер буфера должен быть 2^X
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|