#include "spi.h"
#include "registers.h"
#include "stm32f401xe.h"
void spi_init(spi_t* spi, pin_t csn, SPI_TypeDef* peripheral, uint8_t idx) {
spi->periph = peripheral;
spi->idx = idx;
spi->csn = csn;
}
void spi_master_configure_speed(spi_t *spi,
uint8_t divider) {
reg_write_bits(&spi->periph->CR1, divider << SPI_CR1_BR_Pos, SPI_CR1_BR_Msk);
}
void spi_master_configure(spi_t *spi, bool sw_nss, bool clock_polarity,
bool clock_phase, spi_frame_orientation_t orientation, spi_frame_format_t format) {
reg_write_bits(&spi->periph->CR1,
(sw_nss << SPI_CR1_SSM_Pos) | (format << SPI_CR1_DFF_Pos) |
(orientation << SPI_CR1_LSBFIRST_Pos) |
(0 << SPI_CR1_BIDIMODE_Pos) | (1 << SPI_CR1_MSTR_Pos) |
(clock_polarity << SPI_CR1_CPOL_Pos) | (clock_phase << SPI_CR1_CPHA_Pos),
SPI_CR1_SSM_Msk | SPI_CR1_DFF_Msk | SPI_CR1_LSBFIRST_Msk | SPI_CR1_BIDIMODE_Msk | SPI_CR1_MSTR_Msk | SPI_CR1_CPOL_Msk | SPI_CR1_CPHA_Msk);
spi->periph->CR2 |= SPI_CR2_SSOE | (1 << 3);
}
void spi_master_enable(spi_t *spi, bool enable) {
reg_write_bits(&spi->periph->CR1, enable << SPI_CR1_SPE_Pos, SPI_CR1_SPE);
}
void spi_slave_configure(spi_t *spi, bool sw_nss, bool clock_polarity,
bool clock_phase, spi_frame_orientation_t orientation, spi_frame_format_t format) {
reg_write_bits(&spi->periph->CR1,
(sw_nss << SPI_CR1_SSM_Pos) | (format << SPI_CR1_DFF_Pos) |
(orientation << SPI_CR1_LSBFIRST_Pos) |
(0 << SPI_CR1_BIDIMODE_Pos) | (0 << SPI_CR1_MSTR_Pos) |
(clock_polarity << SPI_CR1_CPOL_Pos) | (clock_phase << SPI_CR1_CPHA_Pos),
SPI_CR1_SSM_Msk | SPI_CR1_DFF_Msk | SPI_CR1_LSBFIRST_Msk | SPI_CR1_BIDIMODE_Msk | SPI_CR1_MSTR_Msk | SPI_CR1_CPOL_Msk | SPI_CR1_CPHA_Msk);
}
void spi_slave_enable(spi_t *spi, bool enable) {
reg_write_bits(&spi->periph->CR1, enable << SPI_CR1_SPE_Pos, SPI_CR1_SPE);
}
uint16_t spi_transmit(spi_t *spi, uint16_t *data, uint16_t size) {
pin_reset(&spi->csn);
for (int16_t i = 0; i < size; i++) {
while (!(spi->periph->SR & SPI_SR_TXE));
uint16_t word = *(data++);
spi->periph->DR = word;
}
return size;
}
uint16_t spi_receive(spi_t *spi, uint16_t *buffer, uint16_t max_size) {
uint16_t size = 0;
while (size < max_size && (spi->periph->SR & SPI_SR_RXNE)) {
*(buffer + (size++)) = (char)(spi->periph->DR & SPI_DR_DR_Msk);
}
return size;
}
void spi_pulse_csn(spi_t *spi) {
pin_set(&spi->csn);
/* pin_reset(&spi->csn); */
}
bool spi_can_transmit(spi_t *spi) {
return (spi->periph->SR & SPI_SR_TXE) != 0;
}
uint16_t spi_can_receive(spi_t *spi) {
return ((spi->periph->SR & SPI_SR_RXNE) != 0) ? 1 : 0;
}
bool spi_enable_interrupt(spi_t *spi, bool tx, bool rx) {
reg_write_bits(&spi->periph->CR2,
(tx << SPI_CR2_TXEIE_Pos) | (rx << SPI_CR2_RXNEIE_Pos),
SPI_CR2_TXEIE | SPI_CR2_RXNEIE);
// TODO: proper irq by idx
NVIC_SetPriority(SPI1_IRQn, 1);
NVIC_EnableIRQ(SPI1_IRQn);
}