Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Зависает прошивка. Реализовал стек для хранения принятых по USB данных и дальнейшей передачи по SSC.
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
Bulat
Принима данные из 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 работает, проблемы возникли, когда я ввел стек.
aaarrr
Цитата(Bulat @ Apr 29 2010, 09:47) *
Не понятно где может повиснуть прошивка, так как останов и повторный запуск SSC работает, проблемы возникли, когда я ввел стек.

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

я могу не запрещать прерывания SSC, а просто его останавливать, также зависать будет. И потом прерывания от EP2 UDP у меня запрещены. Я в главном цикле просто флаг опрашиваю.
Вы имеете в виду мой стек que[] неправильно реализован? Он вроде проще некуда реализован. Проверял, принцип FIFO выполняется, индексы автоматически обнуляются, т.е. работает по кольцу. А что именно в моем стеке не так?
aaarrr
Цитата(Bulat @ Apr 29 2010, 13:24) *
я могу не запрещать прерывания SSC, а просто его останавливать, также зависать будет.

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

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

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

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

У нормального кольцевого буфера нет начала и конца. Степень заполнения определяется по разности указателей (при этом одна ячейка буфера теряется), или по отдельной переменной.
Bulat
Цитата(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, очередь пустая.

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

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

неверно, буфер может быть в этот момент и пуст.
Bulat
Цитата(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, потрудитесь-ка сами с редактированием оформления цитат исходников до их публикации. Так, чтобы они (цитаты) не "распирали" страницу.
Bulat
передача по SSC может не запускаться, только из-за того, что при первом же прерывании от SSC выполняется условие if(head == tail) и передатчик останавливается, не передав даже первого слова. Но по логике того быть не должно или я что-то упустил?
toweroff
Посмотрите, как реализуется кольцевой буфер на примере 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
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.