我是 STM32 世界的新手,我正在尝试让我的 SPI 通信正常工作。我让它在主模式下运行并配置为软件从属管理模式。我使用的是单工通信。仅从主端传输的格式。
当我尝试将数据加载到 SPI 数据寄存器时,据我从调试器中得知,DR 没有任何变化。
任何帮助将不胜感激:
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#define RCC_BASE_ADDR 0x40023800U
#define SPI_1_BASE_ADDR 0x40013000U
#define GPIO_A_BASE_ADDR 0x40020000U
// Register Address Offsets
// RCC
#define RCC_CR_OFFSET 0x00U
#define RCC_AHB_1_EN_OFFSET 0x30U
#define RCC_APB_1_EN_OFFSET 0x40U
#define RCC_APB_2_EN_OFFSET 0x44U
// SPI
#define SPIx_CR_1 0x00U
#define SPIx_CR_2 0x04U
#define SPIx_SR 0x08U
#define SPIx_DR 0x0CU
//#define SPIx_RX 0x14U
//#define SPIx_TX 0x18U
#define SPIx_CFGR 0x1CU
// GPIO
#define MODE_R 0x00U // Mode of GPIO
#define OTYPE_R 0x04U // Output type of GPIO
#define OSPEED_R 0x08U // Output speed
#define PUPD_R 0x0CU // input Config (Pull Up/Down)
#define IDR 0x10U // input Data reg
#define ODR 0x14U // Output Data reg
#define AFLR 0x20U // Alternate function GPIOx[0:7]
#define AFHR 0x24U // Alternate function GPIOx[8:15]
// Bit position offsets
// RCC
//AHB1_EN
#define GPIO_A 0
// APB1_EN
#define SPI_1 12
// SPI
// CR1
#define BIDIMODE 15
#define BIDIOE 14
#define DFF 11
#define RXONLY 10
#define SSM 9
#define SSI 8
#define LSBFIRST 7
#define SPE 6
#define BAUD 5 // [Width : 3]
#define MSTR 2
#define CPOL 1
#define CPHA 0
// CR2
#define TXE 1 // Transfer buffer status
// SR
// GPIOx
// Global vars
// ** RCC
// Enable register for APB2 buss
uint32_t* rcc_apb2_en = (uint32_t*) (RCC_BASE_ADDR + RCC_APB_2_EN_OFFSET);
uint32_t* rcc_ahb1_en = (uint32_t*) (RCC_BASE_ADDR + RCC_AHB_1_EN_OFFSET);
// ** GPIO
// GPIO Mode register
uint32_t* gpio_a_mode = (uint32_t*) (GPIO_A_BASE_ADDR + MODE_R);
// GPIO Alternate function Selection register (LOW)
uint32_t* gpio_aflr = (uint32_t*) (GPIO_A_BASE_ADDR + AFLR);
// ** SPI
// SPI Control Register 1
uint32_t* spi_cr1 = (uint32_t*) (SPI_1_BASE_ADDR + SPIx_CR_1);
// SPI Status register
uint32_t* spi_sr = (uint32_t*) (SPI_1_BASE_ADDR + SPIx_SR);
// SPI data register
uint32_t* spi_dr = (uint32_t*) (SPI_1_BASE_ADDR + SPIx_DR);
// Configure GPIO pins A5 (SCLK) and A7 (MOSI)
void GpioInit(){
// Enable GPIO A on ahb1 bus
*rcc_ahb1_en |= (0x1 << GPIO_A);
// Set the mode for pins 5 and 6 on port A to their alternate functionality
*gpio_a_mode |= (0x2 << 10) | (0x2 << 14);
// Set Pin5 as Serial clock and pin7 as MOSI
*gpio_aflr |= (0x5 << 20) | (0x5 << 28);
}
void SPI_init(){
// Enable SPI on RCC clock
*rcc_apb2_en |= (0x1 << SPI_1);
// Reference to CR1 register in SPI 1 address region
// Configure SPI as for 2 wire unidirectional mode aka full duplex transmission
*spi_cr1 &= ~(0x1 << BIDIMODE);
// Set Data frame as 16 bits wide
*spi_cr1 |= (0x1 << DFF);
// Not implemented
// Internal slave select
// Transfer is LSB first
// Enable SPI
// Enable software slave management
*spi_cr1 |= (0x1 << SSM);
// Set SSI to high to avoid mode fault
*spi_cr1 |= (0x1 << SSI);
// Set baud rate as default DIV2
*spi_cr1 &= ~(0x7 << BAUD);
// Configure as master
*spi_cr1 |= (0x1 << MSTR);
// Set to mode 0
*spi_cr1 &= ~(0x3 << CPHA);
}
void SPIx_write(uint8_t* value, uint8_t len){
// Check the value of the DFF register
uint8_t dff_val = ( (uint32_t)(*spi_cr1) >> DFF) & 0x1;
// 16 Bit transmission
if(dff_val){
while(len > 0){
// Check the status of the TX register
// If empty, then transfer 2 bytes
if(1 /*( (*spi_sr) >> TXE ) & 0x1 */){
// transfer first 2 bytes
// *spi_dr = *((uint16_t*) value);
*spi_dr = *((uint16_t*) value);
// decrement by 2
len-=2;
// Move to next 2 bytes
(uint16_t*)value++;
continue;
}
// If not empty then delay
for(uint8_t i = 0; i < 2; i++);
}
}
// 8 Bit transmission
else{
while(len){
// Check the status of the TX register
// If empty, then transfer 1 byte
if( (*spi_sr) & (0x1 << TXE) ){
// transfer first byte
*spi_dr = *value;
// decrement by 1
len--;
// Move to next byte
value++;
continue;
}
// If not empty then delay
for(uint8_t i = 0; i < 2; i++);
}
}
}
int main(void)
{
char data[] = "hello";
GpioInit(); // Initialize GPIO pins 5 & 7
SPI_init(); // SPI instantiate
// Enable the SPI for communication
*spi_cr1 |= (0x1 << SPE);
// Write to SPI data reg
SPIx_write((uint8_t*)data, strlen(data));
/* Loop forever */
for(;;);
}
uint32_t* rcc_ahb1_en = (uint32_t*) (RCC_BASE_ADDR + RCC_AHB_1_EN_OFFSET);
会无缘无故地消耗 RAM 并添加另一个间接级别。此外,您需要使用一些
volatile
关键字让编译器知道某些内存位置可能会发生变化,而编译器操作不会对其进行任何可见的更改(它们被称为“容易产生副作用”)。
如果你想坚持自己的定义(祝你好运定义 10000 个寄存器),最好是:
#define rcc_ahb1_en ((volatile uint32_t*) (RCC_BASE_ADDR + RCC_AHB_1_EN_OFFSET))
和其他人一样
您给出的问题的唯一症状如下:
当我尝试将数据加载到 SPI 数据寄存器时,据我从调试器中得知,DR 没有任何变化。
你误解了数据寄存器的工作原理。来自 参考手册 第 28.5.4 节:
DR[15:0]:数据寄存器 接收或传输的数据。 数据寄存器分为 2 个缓冲区 - 一个用于写入(发送缓冲区),另一个用于读取(接收缓冲区)。写入数据寄存器将写入 Tx 缓冲区,从数据寄存器读取将返回 Rx 缓冲区中保存的值。
由于您在单工模式下运行(仅传输),接收缓冲区中永远不会有任何内容,因此它始终读取为零。这包括调试器读取数据寄存器。
你可能还有其他问题,但你没有描述。