Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Непонятки с SPI в sam7
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Terminator
Написал "драйвер" SPI master для FreeRTOS с использованием PDC (at91sam7x256).
Передача работает замечательно, а приём частенько "виснет".
Обработчик прерывания
Код
static void __attribute__((naked)) SPI0_ISR( void )
{
    portENTER_SWITCHING_ISR();
        
        tSPI *spi = &all_spi[spi_num];

    unsigned int stat = spi->spi->SPI_SR;
    unsigned int imr = spi->spi->SPI_IMR;
    stat &= imr;
        
    portBASE_TYPE res = pdFALSE;
    if (stat & (AT91C_SPI_ENDRX | AT91C_SPI_ENDTX))
    {
        // сигналим задаче
        res = xSemaphoreGiveFromISR( spi->sem, res);
    }
    
    // запрещаем прерывания
    //spi->spi->SPI_IDR = SPI_INT;
    spi->spi->SPI_IDR = 0xFFFFFFFF;
    
    /* Clear the interrupt. */
    AT91C_BASE_AIC->AIC_EOICR = 0;
    
        portEXIT_SWITCHING_ISR( res );
}


Функция чтения.
Код
// читает из SPI буфер buf размером count
// @param spi_num - номер SPI
// @param buf - куда писать
// @param count - сколько писать
void SPI_Read(unsigned char spi_num, void *buf, unsigned int count)
{
    tSPI *spi = &all_spi[spi_num];

    // чтобы сбросить флаг приёма байта, возможно оставленный прошлой
    // передачей
    spi_num = spi->spi->SPI_RDR;
    
    // готовим PDC
    AT91PS_PDC pPDC = ((AT91PS_PDC) &(spi->spi->SPI_RPR));
    AT91F_PDC_SetRx(pPDC, (char *) buf, count);
    AT91F_PDC_SetTx(pPDC, (char *) buf, count);
    
    // включаем PDC
    AT91F_PDC_EnableTx(pPDC);
    AT91F_PDC_EnableRx(pPDC);

    // разрешаем прерывание
    spi->spi->SPI_IER = AT91C_SPI_ENDRX;
    
    // ждём семафор
    xSemaphoreTake(spi->sem, MAX_BlockTime);
    
    // выключаем PDC
    AT91F_PDC_DisableTx(pPDC);
    AT91F_PDC_DisableRx(pPDC);
}


Вставлял отладочные printf в разных местах, выяснилось, что иногда прерывание не срабатывает. Почему так происходит для меня остаётся загадкой sad.gif

Этот код в основном используется для чтения из флешки, нормально работает пока не попытаюсь прочитать сразу много, под 500кб.
В случайном месте падает. Чтение производится порциями по 530 байт.

Реализация без PDC нормально работает.

Может есть какие-то тонкие моменты при использовании PDC, которые я упустил? help.gif
Alexey V.
тоже были проблемы с SPI+PDC - в даташите в эррате обнаружил, что лучше ножкой чипселекта управлять вручную (иначе чипселект будет подниматься сразу же после передачи последнего байта, независимо от настроек)
Terminator
Цитата(Alexey V. @ Oct 22 2007, 10:28) *
тоже были проблемы с SPI+PDC - в даташите в эррате обнаружил, что лучше ножкой чипселекта управлять вручную (иначе чипселект будет подниматься сразу же после передачи последнего байта, независимо от настроек)

Это я тоже читал. Выставляю чипселекты "руками". Так что отпадает.
_dem
Попробуйте перед запуском PDC прочитать регистр статуса у SPI
Terminator
Цитата(_dem @ Oct 22 2007, 17:23) *
Попробуйте перед запуском PDC прочитать регистр статуса у SPI

Перед запуском всё нормально. А вот после запуска, в момент "смерти", стоит флаг OVRES ...
Смотрел сразу после AT91F_PDC_Enable. Откуда взялся?

Методом научного тыка определил, что достаточно было поменять местами строки
Код
AT91F_PDC_EnableTx(pPDC);
AT91F_PDC_EnableRx(pPDC);

На
Код
AT91F_PDC_EnableRx(pPDC);
AT91F_PDC_EnableTx(pPDC);


Спасибо за наводку.
ljerry
Цитата(Terminator @ Oct 23 2007, 08:17) *
Перед запуском всё нормально. А вот после запуска, в момент "смерти", стоит флаг OVRES ...
Смотрел сразу после AT91F_PDC_Enable. Откуда взялся?

Методом научного тыка определил, что достаточно было поменять местами строки
Код
AT91F_PDC_EnableTx(pPDC);
AT91F_PDC_EnableRx(pPDC);

На
Код
AT91F_PDC_EnableRx(pPDC);
AT91F_PDC_EnableTx(pPDC);


Если, например, между вызовами EnableTx и последующим EnableRx вклинивается прерывание, то может получиться так, что передача (и соответственно прием) уже вовсю идет, буфер приемника переполнен, а приемный PDC еще не запущен. EnableTx обязательно должен выставляться последним.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.