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

 
 
> SAM7X и SPI, непонятки с PDC (где-то лыжи не едут ...)
Terminator
сообщение Jul 20 2009, 10:47
Сообщение #1


Местный
***

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



Есть проект на основе FreeRTOS. Используются оба аппаратных SPI. Все операции через PDC. В драйвере два семафора, один для разделения ресурса SPI, второй для сообщения о прерывании.

Всё было хорошо, но как водится пришла пора делать новый проект. Отличается от старого более навороченным протоколом общения по 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);
}

Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
Dron_Gus
сообщение Jul 21 2009, 05:43
Сообщение #2


Профессионал
*****

Группа: Свой
Сообщений: 1 202
Регистрация: 9-01-05
Из: Санкт-Петербург
Пользователь №: 1 861



Слейва выбираете вручную? Покажите инициализацию СПИ.


--------------------
Если сверху смотреть, то сбоку кажется, что снизу ничего не видно.
Go to the top of the page
 
+Quote Post



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

 


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


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