Всё было хорошо, но как водится пришла пора делать новый проект. Отличается от старого более навороченным протоколом общения по SPI с FPGA (crc и подтверждение доставки). Конечно есть и другие отличия, но до них дело не дошло.
Вот код записи CPU->FPGA
CODE
static uint8_t mcb_buf_w[6];
static uint8_t mcb_buf_r[6];
uint8_t _MCB_Write(tDevSPI *spi, uint16_t addr, uint8_t data)
{
/*
uint8_t *buf;
buf = pvPortMalloc(5+5);
uint8_t *mcb_buf_w;
uint8_t *mcb_buf_r;
mcb_buf_r = &buf[0];
mcb_buf_w = &buf[5];
*/
uint8_t crc = 0;
uint8_t *b = mcb_buf_w;
uint8_t tmp;
tmp = (addr >> 8);
crc = CRC_FUNC(tmp, crc);
*b++ = tmp;
tmp = addr & 0xFF;
crc = CRC_FUNC(tmp, crc);
*b++ = tmp;
tmp = data;
crc = CRC_FUNC(tmp, crc);
*b++ = tmp;
*b++ = ~crc;
debug_array("mcb_write r", mcb_buf_r, 5);
debug_array("mcb_write w", mcb_buf_w, 5);
SPI_Read_Write(spi, mcb_buf_r, mcb_buf_w, 5);
debug_array("mcb_write d r", mcb_buf_r, 5);
debug_array("mcb_write d w", mcb_buf_w, 5);
uint8_t ret = mcb_buf_r[4];
//vPortFree(buf);
return ret;
}
В таком виде не работает, а если раскомментарить выделение и освобождение памяти из кучи, то начинает работать.
Объявление mcb_buf_r и mcb_buf_w за пределами функций я сделал просто так, проверял разные бредовые идеи.
Неработоспособность проявляется следующим образом: данные в FPGA прилетают со сдвигом, т.е. первый байт правильный, вместо второго третий и т.п., в конце вставляется случайный байт. Иногда вместо первого байта отправляется "0".
Всё уже перепробовал, и стеки увеличивал, расположение mcb_buf_r и mcb_buf_w в ОЗУ менял. Другую версию компилятора тоже пробовал. Игрался с оптимизацией. Ничего не помогает. Причём тот же самый драйвер висит на другом аппаратном SPI и через него идёт общение с внешней flash, ниразу никаких проблем небыло.
Может кто сталкивался с подобными случаями?
Компилятор gcc 4.3.3 собранный в gentoo тулзой crossdev. Пробовал на "старой" версии, собранной руками 4.3.1
Код драйвера SPI
CODE
typedef struct {
uint8_t hw_init;
// семафор прерывания
xSemaphoreHandle sem;
// семафор для доступа к SPI
xSemaphoreHandle spi_sem;
// выбранный CS
int8_t cs;
xQueueHandle queue;
AT91PS_SPI spi;
} tSPI;
typedef struct {
// аппаратный SPI
tSPI *hw;
// номер аппаратного CS
uint32_t cs;
// требуемая скорость
uint32_t speed;
uint32_t period;
} tDevSPI;
static void spi_isr(tSPI *spi)
{
*AT91C_AIC_IVR = 0;
tSPITask _task;
portBASE_TYPE res = pdFALSE;
unsigned int stat = spi->spi->SPI_SR & spi->spi->SPI_IMR;
if (stat & AT91C_SPI_ENDTX)
{
portBASE_TYPE tres = xQueueReceiveFromISR(spi->queue, &_task, &res);
if (tres == pdTRUE)
{
// новая порция данных
spi->spi->SPI_TNPR = (uint32_t)_task.buf;
spi->spi->SPI_TNCR = _task.count;
}
else
{
// данные кончились будем ждать окончания передачи
spi->spi->SPI_IDR = AT91C_SPI_ENDTX;
spi->spi->SPI_IER = AT91C_SPI_TXEMPTY;
}
}
else
{
spi->spi->SPI_IDR = stat;
// выключаем PDC
spi->spi->SPI_PTCR = AT91C_PDC_TXTDIS | AT91C_PDC_RXTDIS;
// сигналим задаче
xSemaphoreGiveFromISR(spi->sem, &res);
}
AT91C_BASE_AIC->AIC_EOICR = 0;
if (res)
{
portYIELD_FROM_ISR();
}
}
// обработчик прерывания
static void __attribute__((naked))
SPI0_ISR(void)
{
portSAVE_CONTEXT();
spi_isr(&all_spi[0]);
portRESTORE_CONTEXT();
}
void SPI_Read_Write(tDevSPI *dev, void *read_buf, void *write_buf, uint32_t count)
{
SPI_Take(dev);
DBGSTR("SPI_Read_Write\n");
debug_array("read_buf", read_buf, count);
debug_array("write_buf", write_buf, count);
// чтобы сбросить флаг приёма байта, возможно оставленный прошлой
// передачей
uint8_t tmp = dev->hw->spi->SPI_RDR;
(void)tmp;
if (dev->hw->cs != dev->cs)
SPI_CS_Sel(dev);
// готовим PDC
dev->hw->spi->SPI_RPR = (uint32_t)read_buf;
dev->hw->spi->SPI_RCR = count;
dev->hw->spi->SPI_TPR = (uint32_t)write_buf;
dev->hw->spi->SPI_TCR = count;
// включаем PDC
dev->hw->spi->SPI_PTCR = AT91C_PDC_RXTEN;
dev->hw->spi->SPI_PTCR = AT91C_PDC_TXTEN;
uint32_t rpr = dev->hw->spi->SPI_RPR;
uint32_t tpr = dev->hw->spi->SPI_TPR;
uint32_t rcr = dev->hw->spi->SPI_RCR;
uint32_t tcr = dev->hw->spi->SPI_TCR;
DBG("read buf %x cnt %x\n", rpr, rcr);
DBG("write buf %x cnt %x\n", tpr, tcr);
// разрешаем прерывание
dev->hw->spi->SPI_IER = AT91C_SPI_RXBUFF;
// ждём семафор
xSemaphoreTake(dev->hw->sem, portMAX_DELAY);
rpr = dev->hw->spi->SPI_RPR;
tpr = dev->hw->spi->SPI_TPR;
rcr = dev->hw->spi->SPI_RCR;
tcr = dev->hw->spi->SPI_TCR;
DBG("end read buf %x cnt %x\n", rpr, rcr);
DBG("end write buf %x cnt %x\n", tpr, tcr);
debug_array("end read_buf", read_buf, count);
debug_array("end write_buf", write_buf, count);
SPI_Give(dev);
}