SPI通信在STM32F407VGT6上的应用

huangapple go评论62阅读模式
英文:

SPI Communication On STM32F407VGT6

问题

这是您提供的代码,我将为您提供翻译后的主要部分:

我是相当新于STM32的世界,并正在尝试使我的SPI通信工作。我已将其设置为主模式,并配置为软件从机管理模式。我正在使用单工通信格式,仅从主设备端进行传输。

当我尝试将数据加载到SPI数据寄存器中时,根据调试器的显示,DR 没有任何变化。

对于此问题的任何帮助将不胜感激:

// 下面是代码的一部分,用于配置寄存器地址和位偏移

// 全局变量的初始化以及GPIO和SPI的配置函数

int main(void)
{
    // 初始化并配置GPIO和SPI
    char data[] = "hello";
    GpioInit(); // 初始化GPIO引脚5和7
    SPI_init(); // 初始化SPI
    // 启用SPI进行通信
    *spi_cr1 |= (0x1 << SPE);
    // 写入SPI数据寄存器
    SPIx_write((uint8_t*)data, strlen(data));
    /* 无限循环 */
    for(;;);
}

请注意,此代码片段包括了有关初始化STM32的GPIO和SPI设置的关键信息。如果您需要进一步的翻译或有其他问题,请随时提出。

英文:

I'm pretty new to the STM32 world, and I'm trying to get my SPI communication to work. I have it running in Master mode and configured to Software Slave management mode. And I'm using a simplex comm. format with transmission only from the Master side.

When I try to load data into may SPI Data Register, there's no change to the DR as far as I can tell from the debugger.

Any help with this would be greatly appreciated:

#include &lt;stdint.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#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 &lt;&lt; GPIO_A);

	// Set the mode for pins 5 and 6 on port A to their alternate functionality
	*gpio_a_mode |= (0x2 &lt;&lt; 10) | (0x2 &lt;&lt; 14);

	// Set Pin5 as Serial clock and pin7 as MOSI
	*gpio_aflr |= (0x5 &lt;&lt; 20) | (0x5 &lt;&lt; 28);
}

void SPI_init(){
	// Enable SPI on RCC clock
	*rcc_apb2_en |= (0x1 &lt;&lt; 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 &amp;= ~(0x1 &lt;&lt; BIDIMODE);

	// Set Data frame as 16 bits wide
	*spi_cr1 |= (0x1 &lt;&lt; DFF);

	// Not implemented

		// Internal slave select

		// Transfer is LSB first

		// Enable SPI

	// Enable software slave management
	*spi_cr1 |= (0x1 &lt;&lt; SSM);

	// Set SSI to high to avoid mode fault
	*spi_cr1 |= (0x1 &lt;&lt; SSI);
	// Set baud rate as default DIV2
	*spi_cr1 &amp;= ~(0x7 &lt;&lt; BAUD);

	// Configure as master
	*spi_cr1 |= (0x1 &lt;&lt; MSTR);
	//	Set to mode 0
	*spi_cr1 &amp;= ~(0x3 &lt;&lt; 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) &gt;&gt; DFF) &amp; 0x1;
	// 16 Bit transmission
	if(dff_val){
		while(len &gt; 0){
			// Check the status of the TX register
			// If empty, then transfer 2 bytes
			if(1 /*( (*spi_sr)  &gt;&gt; TXE ) &amp; 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 &lt; 2; i++);
		}
	}
	// 8 Bit transmission
	else{
		while(len){
			// Check the status of the TX register
			// If empty, then transfer 1 byte
			if( (*spi_sr) &amp; (0x1 &lt;&lt; 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 &lt; 2; i++);
		}
	}

}


int main(void)
{
	char data[] = &quot;hello&quot;;
	GpioInit();		// Initialize GPIO pins 5 &amp; 7
	SPI_init();			// SPI instantiate
	// Enable the SPI for communication
	*spi_cr1 |= (0x1 &lt;&lt; SPE);
    // Write to SPI data reg
	SPIx_write((uint8_t*)data, strlen(data));
    /* Loop forever */
	for(;;);
}

答案1

得分: 1

  1. 避免重复造轮子并使用STM提供的CMSIS定义。你的尝试相当幼稚。举例来说:
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))

其他的也是一样的。

英文:
  1. Avoid reinventing the wheel and use STM-provided CMSIS definitions. Your attempt is quite naive. For example:
uint32_t* rcc_ahb1_en = (uint32_t*) (RCC_BASE_ADDR + RCC_AHB_1_EN_OFFSET);

will consume RAM for no reason and adds another level of indirection. Additionally, you need to use some volatile keywords to let compiler know that some memory locations may change without any visible to compiler operations changing it (they are called "side effects prone").

If you want to stick to your own definitions (good luck defining 10000 registers) it would be much better to:

#define rcc_ahb1_en ((volatile uint32_t*) (RCC_BASE_ADDR + RCC_AHB_1_EN_OFFSET))

and the same with all others

答案2

得分: 0

以下是要翻译的内容:

你提供的问题唯一的症状如下:

> 当我尝试加载数据到SPI数据寄存器时,从调试器中看,DR 没有发生变化。

你对数据寄存器的工作方式有误解。参考手册的第28.5.4节(链接)中有说明:

> DR[15:0]:数据寄存器
> 用于接收或传输的数据。
> 数据寄存器分为两个缓冲区 - 一个用于写入(传输缓冲区),另一个用于读取(接收缓冲区)。对数据寄存器的写入将写入Tx缓冲区,对数据寄存器的读取将返回Rx缓冲区中保存的值。

由于您在单工模式下运行(仅传输),接收缓冲区中永远不会有任何内容,因此它将始终读取为零。这也包括调试器读取数据寄存器。

您可能存在其他问题,但您尚未描述它们。

英文:

The only symptom of your problem that you have given is the following:

> When I try to load data into may SPI Data Register, there's no change to the DR as far as I can tell from the debugger.

You are misunderstanding how the data register works. From the reference manual at section 28.5.4:

> DR[15:0]: Data register
> Data received or to be transmitted.
> The data register is split into 2 buffers - one for writing (Transmit Buffer) and another one for reading (Receive buffer). A write to the data register will write into the Tx buffer and a read from the data register will return the value held in the Rx buffer.

Since you are running in simplex mode (only transmitting), there will never be anything in the receive buffer, so it will always read as zero. This includes the debugger reading the data register.

You may have other problems, but you have not described them.

huangapple
  • 本文由 发表于 2023年3月20日 23:44:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/75792404.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定