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

 
 
 
Reply to this topicStart new topic
> Непонятки с SPI в sam7, PDC...
Terminator
сообщение Oct 22 2007, 02:38
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 209
Регистрация: 7-12-04
Из: Томск
Пользователь №: 1 382



Написал "драйвер" 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
Go to the top of the page
 
+Quote Post
Alexey V.
сообщение Oct 22 2007, 03:28
Сообщение #2


Участник
*

Группа: Новичок
Сообщений: 24
Регистрация: 10-05-06
Из: Russia, Tomsk
Пользователь №: 16 936



тоже были проблемы с SPI+PDC - в даташите в эррате обнаружил, что лучше ножкой чипселекта управлять вручную (иначе чипселект будет подниматься сразу же после передачи последнего байта, независимо от настроек)
Go to the top of the page
 
+Quote Post
Terminator
сообщение Oct 22 2007, 03:45
Сообщение #3


Местный
***

Группа: Участник
Сообщений: 209
Регистрация: 7-12-04
Из: Томск
Пользователь №: 1 382



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

Это я тоже читал. Выставляю чипселекты "руками". Так что отпадает.
Go to the top of the page
 
+Quote Post
_dem
сообщение Oct 22 2007, 10:23
Сообщение #4


Местный
***

Группа: Свой
Сообщений: 263
Регистрация: 2-02-07
Из: CN, Ukraine
Пользователь №: 24 970



Попробуйте перед запуском PDC прочитать регистр статуса у SPI
Go to the top of the page
 
+Quote Post
Terminator
сообщение Oct 23 2007, 04:17
Сообщение #5


Местный
***

Группа: Участник
Сообщений: 209
Регистрация: 7-12-04
Из: Томск
Пользователь №: 1 382



Цитата(_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);


Спасибо за наводку.

Сообщение отредактировал Terminator - Oct 23 2007, 04:20
Go to the top of the page
 
+Quote Post
ljerry
сообщение Oct 23 2007, 08:23
Сообщение #6


Участник
*

Группа: Участник
Сообщений: 26
Регистрация: 7-02-06
Из: Зеленоград
Пользователь №: 14 071



Цитата(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 обязательно должен выставляться последним.
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 19th June 2025 - 09:56
Рейтинг@Mail.ru


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