Перейти к содержимому

#21. Инициализация и тестирование (SPI)

В этой части мы протестируем драйвер SPI с простым интерфейсом, показанным на рисунке ниже. Стандартная периферийная библиотека определяет три устройства SPI (SPI1, SPI2 и SPI3) и 8 возможных часовых делителей тактовых импульсов в stm32f10x_spi.h — для 24-мегагерцовой части платы, делитель на 8 приводит к тактовой частоте SPI 3 МГц (24/8). Мы используем делители на 64, 8 и 2 для медленной, средней и быстрой скорости соответственно. Этот интерфейс обеспечивает инициализацию любого из этих трех устройств с относительно общей конфигурацией. Существует одна операция передачи данных, которая позволяет обмениваться буферами данных с устройством SPI. Технически, каждая передача данных является двунаправленной, но многие устройства не используют эту возможность. Таким образом, операции чтения / записи принимают нулевые указатели для буфера отправки или приема. Устройство SPI также поддерживает 16-битную передачу, поэтому наш интерфейс обеспечивает 16-битную функцию чтения / записи. Наконец, интерфейс позволяет оперативно изменять скорость передачи. Такое изменение может быть необходимо, если на шине есть два ведомых устройства с разными скоростями.

enum spiSpeed { SPI_SLOW , SPI_MEDIUM , SPI_FAST };
void spiInit(SPI_TypeDef* SPIx);
int spiReadWrite(SPI_TypeDef* SPIx, uint8_t *rbuf,
const uint8_t *tbuf, int cnt,
enum spiSpeed speed);
int spiReadWrite16(SPI_TypeDef* SPIx, uint16_t *rbuf,
const uint16_t *tbuf, int cnt,
enum spiSpeed speed);

Инициализация для модуля SPI следует той же общей последовательности, необходимой для любого периферийного устройства —

  1. Включение тактирования для периферийных и связанных портов GPIO.
  2. Настройка контактов GPIO.
  3. Настройка устройства.
SPI Pin Configuration

Конфигурация необходимых контактов показана выше. Не показаны выводы, доступные для аппаратного управления линией выбора ведомого, потому что мы реализуем это с помощью программного управления. Процесс инициализации показан в ниже. Нас интересует только один режим работы — STM32, действующий как мастер. В более сложных системах может потребоваться значительно изменить эту процедуру, например, передав SPI_InitStructure. Процедура инициализации следует последовательности, показанной ранее, и легко расширяется для поддержки дополнительных периферийных устройств SPI.

static const uint16_t speeds[] = {
[SPI_SLOW] = SPI_BaudRatePrescaler_64 ,
[SPI_MEDIUM] = SPI_BaudRatePrescaler_8 ,
[SPI_FAST] = SPI_BaudRatePrescaler_2};
void spiInit(SPI_TypeDef *SPIx)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_StructInit(&GPIO_InitStructure);
SPI_StructInit(&SPI_InitStructure);
if (SPIx == SPI2) {
/* Enable clocks , configure pins
...
*/
} else {
return;
}
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = speeds[SPI_SLOW];
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPIx, &SPI_InitStructure);
SPI_Cmd(SPIx, ENABLE);
}

Наш базовый модуль SPI поддерживает отдельные типы транзакций — чтение / запись, что показано ниже. Процедура чтения / записи перебирает количество байтов данных, подлежащих обмену. Каждая итерация состоит из отправки байта, ожидания завершения получателем и получения байта. В случае подпрограммы только для записи внутренний буфер используется для перехвата и отбрасывания принятого байта. Точно так же подпрограмма только для чтения передает последовательность 0xff (эффективно бездействующих) байтов при получении. 16-разрядные подпрограммы работают путем временного изменения конфигурации для поддержки 16-разрядных передач с использованием следующих системных вызовов:

SPI_DataSizeConfig(SPIx, SPI_DataSize_16b);
SPI_DataSizeConfig(SPIx, SPI_DataSize_8b);

SPI Read/Write:

int spiReadWrite(SPI_TypeDef* SPIx, uint8_t *rbuf,
const uint8_t *tbuf, int cnt, enum spiSpeed speed)
{
int i;
SPIx->CR1 = (SPIx->CR1 & ~SPI_BaudRatePrescaler_256) |
speeds[speed];
for (i = 0; i < cnt; i++){
if (tbuf) {
SPI_I2S_SendData(SPIx, *tbuf++);
} else {
SPI_I2S_SendData(SPIx, 0xff);
}
while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET);
if (rbuf) {
*rbuf++ = SPI_I2S_ReceiveData(SPIx);
} else {
SPI_I2S_ReceiveData(SPIx);
}
}
return i;
}

SPI Loopback Test :

uint8_t txbuf[4], rxbuf[4];
uint16_t txbuf16[4], rxbuf16[4];
void main()
{
int i, j;
csInit(); // Initialize chip select PC03
spiInit(SPI2);
for (i = 0; i < 8; i++) {
for (j = 0; j < 4; j++)
txbuf[j] = i*4 + j;
GPIO_WriteBit(GPIOC , GPIO_Pin_3 , 0);
spiReadWrite(SPI2, rxbuf , txbuf , 4, SPI_SLOW);
GPIO_WriteBit(GPIOC , GPIO_Pin_3 , 1);
for (j = 0; j < 4; j++)
if (rxbuf[j] != txbuf[j])
assert_failed(__FILE__ , __LINE__);
}
for (i = 0; i < 8; i++) {
for (j = 0; j < 4; j++)
txbuf16[j] = i*4 + j + (i << 8);
GPIO_WriteBit(GPIOC , GPIO_Pin_3 , 0);
spiReadWrite16(SPI2, rxbuf16 , txbuf16 , 4, SPI_SLOW);
GPIO_WriteBit(GPIOC , GPIO_Pin_3 , 1);
for (j = 0; j < 4; j++)
if (rxbuf16[j] != txbuf16[j])
assert_failed(__FILE__ , __LINE__);
}
}

Добавить комментарий