Передача работает замечательно, а приём частенько "виснет".
Обработчик прерывания
Код
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 );
}
{
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);
}
// @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 в разных местах, выяснилось, что иногда прерывание не срабатывает. Почему так происходит для меня остаётся загадкой

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