Протокол SPI и микроконтроллер STM8
Следующий код позволяет использовать периферию, работающую по протоколу SPI, совместно с микроконтроллером STM8. Шина SPI это последовательный периферийный интерфейс, она использует для работы 4 вывода микроконтроллера.
Пример написан для использования с микроконтроллером STM8S208MB и компилятором Raisonance.
- MOSI или SI — Выход для передачи данных от ведущего устройства ведомому;
- MISO или SO — Вход для передачи данных от ведомого устройства ведущему;
- SCLK или SCK — Выход для передачи тактового сигнала для ведомых устройств;
- CS или SS — выбор ведомой микросхемы, с которой ведётся обмен данными.
Управлять выходами CS понадобится в том случае, если на шине SPI несколько устройств. Тогда сколько устройств, столько и отдельных портов задействовано под сигналы CS. Каждый выбирает свою микросхему. Обычно для выбора микросхемы надо подать низкий уровень на CS. Если же устройство всего одно, тогда можно прямо на схеме подать туда низкий уровень, а управление CS'ом из микроконтроллера вообще не использовать. Тогда в микроконтроллере останется свободным лишний порт ввода-вывода.
Допустим, мне надо сконфигурировать SPI для считывания данных с датчика угла поворота KMA200. Тогда я делаю так:
#define SELECT_PIN GPIO_PIN_3 #define CLK_PIN GPIO_PIN_5 #define DATA_PIN GPIO_PIN_7 GPIO_Init (GPIOC, SELECT_PIN, GPIO_MODE_OUT_PP_HIGH_FAST); GPIO_Init (GPIOC, DATA_PIN, GPIO_MODE_IN_FL_NO_IT); GPIO_Init (GPIOC, CLK_PIN, GPIO_MODE_OUT_PP_HIGH_FAST);
Я ничего не записываю в датчик, поэтому порт, отвечающий за выход SPI не сконфигурирован. Да он может быть даже не подведён к самому датчику, так как требуется только читать. Так что DATA_PIN настроен на ввод, SELECT_PIN и CLK_PIN — на вывод. SELECT_PIN это вышеописанный CS (SS).
Теперь конфигурация и включение SPI на STM8:
SPI_Init ( SPI_FIRSTBIT_MSB, SPI_BAUDRATEPRESCALER_256, SPI_MODE_MASTER, SPI_CLOCKPOLARITY_HIGH, SPI_CLOCKPHASE_2EDGE, SPI_DATADIRECTION_2LINES_FULLDUPLEX, SPI_NSS_SOFT, 0x00 ); SPI_Cmd(ENABLE);
По идее, если нужно только чтение, то есть режим SPI_DATADIRECTION_1LINE_RX. Однако, в таком режиме у меня датчик отказался отзываться. Пришлось использовать режим SPI_DATADIRECTION_2LINES_FULLDUPLEX и имитировать запись (ничего не значащий байт 0xFF), в этом случае чтение с датчика после записи проходит нормально. Это связано с какими-то внутренними нюансами работы модуля SPI в микроконтроллере, с тем, как генерируются прерывания чтения и записи SPI. Не стал в этом досконально разбираться, просто добился правильной работы, и достаточно. В общем, чтобы прочитать байт по протоколу SPI делаю так:
u8 SPI_ReadByte(void) { /* Ждём очистки регистра DR */ while ((SPI->SR & (u8)SPI_FLAG_TXE) == RESET) { ; } /* Послать байт */ SPI->DR = 0xFF; /* Ждём приёма байта */ while ((SPI->SR & (u8)SPI_FLAG_RXNE) == RESET) { ; } /* Возвратить принятый байт */ return (u8)SPI->DR; }
Этот же код годится и тогда, когда мне надо действительно что-то записать в SPI. Но в данном случае, раз на схеме MOSI даже не соединён с датчиком, реальной записи не происходит.
Теперь можно использовать этот код для опроса датчика KMA200. Об этом в следующей заметке. Этот же код с изменениями, касающиеся 16-битного SPI, использован в заметке про AS5050.
Автор: амдф
Дата: 29.09.2012
Избранное
Остальное
Лента atom