GPS Device
Loading...
Searching...
No Matches
stm32f401re_spi.c
Go to the documentation of this file.
1
10
11#include "stm32f401re_spi.h"
12#include "stm32f401re.h"
13#include "stm32f401re_rcc.h"
14
15/* ---- Forward declaration for internal helper ---- */
16static void spi_set_pclk(SPI_REGDEF_ts const *instance, EN_STATUS_te en_status);
17
22
24void spi_init(SPI_CFG_ts *spi_cfg) {
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}
70
72void spi_deinit(SPI_REGDEF_ts const *instance) {
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}
88
90void spi_send(SPI_REGDEF_ts *instance, uint8_t *tx_buffer, uint32_t len) {
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}
113
115void spi_receive(SPI_REGDEF_ts *instance, uint8_t *rx_buffer, uint32_t len) {
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}
141
144 spi_instance->SPI_CR1 &= ~(0x7 << SPI_CR1_BR);
145 spi_instance->SPI_CR1 |= (pclk_div << SPI_CR1_BR);
146}
147
149void spi_set_comm(SPI_REGDEF_ts *instance, EN_STATUS_te en_status) {
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}
160
162
167
181static void spi_set_pclk(SPI_REGDEF_ts const *instance, EN_STATUS_te en_status) {
182 if(instance == SPI1) {
184 }
185 else if(instance == SPI2) {
187 }
188 else if(instance == SPI3) {
190 }
191 else if(instance == SPI4) {
193 }
194}
195
EN_STATUS_te
Represents an enabled or disabled state.
Definition common.h:95
@ ENABLE
Definition common.h:100
@ DISABLE
Definition common.h:97
void rcc_set_pclk_apb2(RCC_APB2ENR_te periph_position, EN_STATUS_te en_status)
Enables or disables the peripheral clock for an APB2 peripheral.
void rcc_reset_periph_apb2(RCC_APB2RSTR_te periph_position)
Resets an APB2 peripheral via RCC_APB2RSTR.
void rcc_set_pclk_apb1(RCC_APB1ENR_te periph_position, EN_STATUS_te en_status)
Enables or disables the peripheral clock for an APB1 peripheral.
void rcc_reset_periph_apb1(RCC_APB1RSTR_te periph_position)
Resets an APB1 peripheral via RCC_APB1RSTR.
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.
void spi_set_comm(SPI_REGDEF_ts *instance, EN_STATUS_te en_status)
Enables or disables the SPI peripheral.
void spi_send(SPI_REGDEF_ts *instance, uint8_t *tx_buffer, uint32_t len)
Blocking SPI transmit.
void spi_deinit(SPI_REGDEF_ts const *instance)
Deinitializes the SPI peripheral and disables its clock.
void spi_init(SPI_CFG_ts *spi_cfg)
Initializes the SPI peripheral with the given configuration.
void spi_receive(SPI_REGDEF_ts *instance, uint8_t *rx_buffer, uint32_t len)
Blocking SPI receive.
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.
SPI_MASTER_SCLK_SPEED_te
SPI master clock speed as a division of the peripheral clock (PCLK).
@ SPI_MODE_SLAVE
@ SPI_MODE_MASTER
@ SPI_SLAVE_SELECT_MODE_HW
#define SPI4
#define SPI3
#define SPI1
#define SPI2
@ SPI_CR1_MSTR
@ SPI_CR1_SSI
@ SPI_CR1_SSM
@ SPI_CR1_CPHA
@ SPI_CR1_CPOL
@ SPI_CR1_SPE
@ SPI_CR1_BR
@ SPI_CR1_LSBFIRST
@ SPI_CR1_DFF
@ SPI_CR2_SSOE
@ RCC_APB2ENR_SPI1EN
@ RCC_APB2ENR_SPI4EN
@ RCC_APB2RSTR_SPI4RST
@ RCC_APB2RSTR_SPI1RST
@ RCC_APB1ENR_SPI3EN
@ RCC_APB1ENR_SPI2EN
@ RCC_APB1RSTR_SPI2RST
@ RCC_APB1RSTR_SPI3RST
@ SPI_SR_TXE
@ SPI_SR_BSY
@ SPI_SR_RXNE
STM32F401RE MCU-specific peripheral register definitions and bit position enumerations.
STM32F401RE RCC driver public API.
STM32F401RE SPI driver public API.
Configuration structure for initializing an SPI peripheral.
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
SPI peripheral register map.
uint32_t volatile SPI_CR2
uint32_t volatile SPI_DR
uint32_t volatile SPI_SR
uint32_t volatile SPI_CR1