GPS Device
Loading...
Searching...
No Matches
SPI Public API

Public functions to interact with the SPI peripheral. More...

Collaboration diagram for SPI Public API:

Functions

void spi_init (SPI_CFG_ts *spi_cfg)
 Initializes the SPI peripheral with the given configuration.
void spi_deinit (SPI_REGDEF_ts const *spi_instance)
 Deinitializes the SPI peripheral and disables its clock.
void spi_send (SPI_REGDEF_ts *spi_instance, uint8_t *tx_buffer, uint32_t len)
 Blocking SPI transmit. Sends len bytes from tx_buffer.
void spi_receive (SPI_REGDEF_ts *spi_instance, uint8_t *rx_buffer, uint32_t len)
 Blocking SPI receive. Reads len bytes into rx_buffer.
void spi_set_pclk_div (SPI_REGDEF_ts *spi_instance, SPI_MASTER_SCLK_SPEED_te pclk_div)
 Changes the SPI master clock speed divisor at runtime.
void spi_set_comm (SPI_REGDEF_ts *spi_instance, EN_STATUS_te en_status)
 Enables or disables the SPI peripheral (SPE bit).

Detailed Description

Public functions to interact with the SPI peripheral.

Function Documentation

◆ spi_init()

void spi_init ( SPI_CFG_ts * spi_cfg)

Initializes the SPI peripheral with the given configuration.

Enables the peripheral clock and configures data frame format, clock polarity, clock phase, bit order, slave select mode, master/slave mode, and (in master mode) the SCK speed. Does not enable the peripheral for communication; call spi_set_comm with ENABLE to do so.

Default values if fields are zero-initialized:

  • Mode: slave
  • Data frame: 8-bit
  • Clock polarity: idle low (CPOL = 0)
  • Clock phase: first transition (CPHA = 0)
  • Bit order: MSB first
  • Slave select: hardware
  • Master speed: PCLK / 2
Parameters
[in]spi_cfgPointer to the SPI configuration structure.
Note
It is recommended to zero-initialize SPI_CFG_ts before use.
See also
spi_init

Definition at line 24 of file stm32f401re_spi.c.

24 {
25 spi_set_pclk(spi_cfg->instance, ENABLE);
26
27 // Configure data frame format (8-bit or 16-bit)
28 spi_cfg->instance->SPI_CR1 &= ~(0x1 << SPI_CR1_DFF);
29 spi_cfg->instance->SPI_CR1 |= (spi_cfg->data_frame_format << SPI_CR1_DFF);
30
31 // Configure clock polarity (CPOL)
32 spi_cfg->instance->SPI_CR1 &= ~(0x1 << SPI_CR1_CPOL);
33 spi_cfg->instance->SPI_CR1 |= (spi_cfg->clock_polarity << SPI_CR1_CPOL);
34
35 // Configure clock phase (CPHA)
36 spi_cfg->instance->SPI_CR1 &= ~(0x1 << SPI_CR1_CPHA);
37 spi_cfg->instance->SPI_CR1 |= (spi_cfg->clock_phase << SPI_CR1_CPHA);
38
39 // Configure bit order (MSB or LSB first)
40 spi_cfg->instance->SPI_CR1 &= ~(0x1 << SPI_CR1_LSBFIRST);
41 spi_cfg->instance->SPI_CR1 |= (spi_cfg->bit_first << SPI_CR1_LSBFIRST);
42
43 // Configure slave select management (HW or SW)
44 spi_cfg->instance->SPI_CR1 &= ~(0b1 << SPI_CR1_SSM);
45 spi_cfg->instance->SPI_CR1 |= (spi_cfg->slave_select_mode << SPI_CR1_SSM);
46
47 if(spi_cfg->mode == SPI_MODE_MASTER) {
48 // Set SSI to prevent MODF fault in software NSS mode
49 spi_cfg->instance->SPI_CR1 |= (0x1 << SPI_CR1_SSI);
50
51 // Enable SSOE for hardware NSS output
53 spi_cfg->instance->SPI_CR2 &= ~(0x1 << SPI_CR2_SSOE);
54 spi_cfg->instance->SPI_CR2 |= (0x1 << SPI_CR2_SSOE);
55 }
56
57 // Configure master SCK speed (BR bits)
58 spi_cfg->instance->SPI_CR1 &= ~(0x07 << SPI_CR1_BR);
59 spi_cfg->instance->SPI_CR1 |= (spi_cfg->master_sclk_speed << SPI_CR1_BR);
60 }
61 else if(spi_cfg->mode == SPI_MODE_SLAVE) {
62 // Clear SSI to pull NSS internally low in slave mode
63 spi_cfg->instance->SPI_CR1 &= ~(0x1 << SPI_CR1_SSI);
64 }
65
66 // Set master/slave mode
67 spi_cfg->instance->SPI_CR1 &= ~(0x1 << SPI_CR1_MSTR);
68 spi_cfg->instance->SPI_CR1 |= (spi_cfg->mode << SPI_CR1_MSTR);
69}
@ ENABLE
Definition common.h:100
static void spi_set_pclk(SPI_REGDEF_ts const *instance, EN_STATUS_te en_status)
Enables or disables the peripheral clock for an SPI instance.
@ SPI_MODE_SLAVE
@ SPI_MODE_MASTER
@ SPI_SLAVE_SELECT_MODE_HW
@ SPI_CR1_MSTR
@ SPI_CR1_SSI
@ SPI_CR1_SSM
@ SPI_CR1_CPHA
@ SPI_CR1_CPOL
@ SPI_CR1_BR
@ SPI_CR1_LSBFIRST
@ SPI_CR1_DFF
@ SPI_CR2_SSOE
SPI_CLOCK_POLARITY_te clock_polarity
SPI_SLAVE_SELECT_MODE_te slave_select_mode
SPI_REGDEF_ts * instance
SPI_MASTER_SCLK_SPEED_te master_sclk_speed
SPI_DATA_FRAME_FORMAT_te data_frame_format
SPI_CLOCK_PHASE_te clock_phase
SPI_MODE_te mode
SPI_BIT_FIRST_te bit_first
uint32_t volatile SPI_CR2
uint32_t volatile SPI_CR1
Here is the call graph for this function:
Here is the caller graph for this function:

◆ spi_deinit()

void spi_deinit ( SPI_REGDEF_ts const * instance)

Deinitializes the SPI peripheral and disables its clock.

Triggers an RCC peripheral reset for the given instance and then disables the peripheral clock.

Parameters
[in]spi_instancePointer to the SPI instance to deinitialize.
See also
spi_deinit

Definition at line 72 of file stm32f401re_spi.c.

72 {
73 if(instance == SPI1) {
75 }
76 else if(instance == SPI2) {
78 }
79 else if(instance == SPI3) {
81 }
82 else if(instance == SPI4) {
84 }
85
86 spi_set_pclk(instance, DISABLE);
87}
@ DISABLE
Definition common.h:97
void rcc_reset_periph_apb2(RCC_APB2RSTR_te periph_position)
Resets an APB2 peripheral via RCC_APB2RSTR.
void rcc_reset_periph_apb1(RCC_APB1RSTR_te periph_position)
Resets an APB1 peripheral via RCC_APB1RSTR.
#define SPI4
#define SPI3
#define SPI1
#define SPI2
@ RCC_APB2RSTR_SPI4RST
@ RCC_APB2RSTR_SPI1RST
@ RCC_APB1RSTR_SPI2RST
@ RCC_APB1RSTR_SPI3RST
Here is the call graph for this function:
Here is the caller graph for this function:

◆ spi_send()

void spi_send ( SPI_REGDEF_ts * instance,
uint8_t * tx_buffer,
uint32_t len )

Blocking SPI transmit. Sends len bytes from tx_buffer.

Transmits data one frame at a time, polling TXE before each write and RXNE after each write to drain the receive FIFO (required in full-duplex mode to prevent overrun). Supports both 8-bit and 16-bit frame formats.

Parameters
[in]spi_instancePointer to the SPI peripheral instance.
[in]tx_bufferPointer to the transmit data buffer.
[in]lenNumber of bytes to transmit. Must be even for 16-bit frames.
Note
The peripheral must be enabled via spi_set_comm before calling this function.

Blocking SPI transmit. Sends len bytes from tx_buffer.

See also
spi_send

Definition at line 90 of file stm32f401re_spi.c.

90 {
91 while(len != 0) {
92 if(((instance->SPI_CR1 >> SPI_CR1_DFF) & 0x1) == 0) {
93 // 8-bit frame: wait for TXE, write one byte
94 while(!((instance->SPI_SR >> SPI_SR_TXE) & 0x1));
95 instance->SPI_DR = *tx_buffer;
96 tx_buffer++;
97 len--;
98 }
99 else {
100 // 16-bit frame: wait for TXE, write two bytes
101 while(!((instance->SPI_SR >> SPI_SR_TXE) & 0x1));
102 instance->SPI_DR = *((uint16_t*)tx_buffer);
103 tx_buffer += 2;
104 len -= 2;
105 }
106
107 // Drain receive FIFO to prevent overrun in full-duplex mode
108 while(!((instance->SPI_SR >> SPI_SR_RXNE) & 0x1));
109 uint16_t dummy_rx = instance->SPI_DR;
110 (void)dummy_rx;
111 }
112}
@ SPI_SR_TXE
@ SPI_SR_RXNE
uint32_t volatile SPI_DR
uint32_t volatile SPI_SR
Here is the caller graph for this function:

◆ spi_receive()

void spi_receive ( SPI_REGDEF_ts * instance,
uint8_t * rx_buffer,
uint32_t len )

Blocking SPI receive. Reads len bytes into rx_buffer.

Receives data by transmitting dummy bytes (0xFF) to generate the SCK clock signal, then reads the received byte from the data register. Supports both 8-bit and 16-bit frame formats.

Parameters
[in]spi_instancePointer to the SPI peripheral instance.
[out]rx_bufferPointer to the receive data buffer.
[in]lenNumber of bytes to receive. Must be even for 16-bit frames.
Note
The peripheral must be enabled via spi_set_comm before calling this function.

Blocking SPI receive. Reads len bytes into rx_buffer.

See also
spi_receive

Definition at line 115 of file stm32f401re_spi.c.

115 {
116 uint16_t dummy_tx = 0xFFFF;
117
118 while(len != 0) {
119 if(((instance->SPI_CR1 >> SPI_CR1_DFF) & 0x1) == 0) {
120 // 8-bit frame: send dummy byte to generate clock, then read
121 instance->SPI_DR = (uint8_t)dummy_tx;
122 while(!((instance->SPI_SR >> SPI_SR_TXE) & 0x1));
123
124 while(!((instance->SPI_SR >> SPI_SR_RXNE) & 0x1));
125 *rx_buffer = instance->SPI_DR;
126 len--;
127 rx_buffer++;
128 }
129 else {
130 // 16-bit frame: send dummy word to generate clock, then read
131 instance->SPI_DR = dummy_tx;
132 while(!((instance->SPI_SR >> SPI_SR_TXE) & 0x1));
133
134 while(!((instance->SPI_SR >> SPI_SR_RXNE) & 0x1));
135 *((uint16_t*)rx_buffer) = instance->SPI_DR;
136 len -= 2;
137 rx_buffer += 2;
138 }
139 }
140}
Here is the caller graph for this function:

◆ spi_set_pclk_div()

void spi_set_pclk_div ( SPI_REGDEF_ts * spi_instance,
SPI_MASTER_SCLK_SPEED_te pclk_div )

Changes the SPI master clock speed divisor at runtime.

Updates the BR field in SPI_CR1 without a full re-initialization. Used by the SD card driver to ramp the SCK from the slow initialization speed (100–400 kHz) to the maximum speed after card initialization.

Parameters
[in]spi_instancePointer to the SPI peripheral instance.
[in]pclk_divThe new clock divisor to apply.
Note
The peripheral should be disabled (SPE = 0) before changing BR. In practice this is called between transactions so the peripheral is idle, but be cautious if calling mid-transaction.
See also
spi_set_pclk_div

Definition at line 143 of file stm32f401re_spi.c.

143 {
144 spi_instance->SPI_CR1 &= ~(0x7 << SPI_CR1_BR);
145 spi_instance->SPI_CR1 |= (pclk_div << SPI_CR1_BR);
146}
Here is the caller graph for this function:

◆ spi_set_comm()

void spi_set_comm ( SPI_REGDEF_ts * instance,
EN_STATUS_te en_status )

Enables or disables the SPI peripheral (SPE bit).

  • ENABLE: sets SPE, activating the peripheral for communication. Must be called before the first spi_send or spi_receive.
  • DISABLE: waits for the BSY flag to clear (transfer complete), then clears SPE. Must be called after the last transfer.
Parameters
[in]spi_instancePointer to the SPI peripheral instance.
[in]en_statusENABLE to activate, DISABLE to deactivate.

Enables or disables the SPI peripheral (SPE bit).

See also
spi_set_comm

Definition at line 149 of file stm32f401re_spi.c.

149 {
150 if(en_status == ENABLE) {
151 instance->SPI_CR1 &= ~(0x1 << SPI_CR1_SPE);
152 instance->SPI_CR1 |= (0x1 << SPI_CR1_SPE);
153 }
154 else if(en_status == DISABLE) {
155 // Wait for any ongoing transfer to complete before clearing SPE
156 while((instance->SPI_SR >> SPI_SR_BSY) & 0x01);
157 instance->SPI_CR1 &= ~(0x1 << SPI_CR1_SPE);
158 }
159}
@ SPI_CR1_SPE
@ SPI_SR_BSY
Here is the caller graph for this function: