我想在STM32H7 MCU上配置一个简单的基于中断的SPI从发送器/接收器。尽管我对旧系列的STM32 ARM MCU有相当多的经验,但H7系列似乎有很多不同之处,需要花费很多精力来重新学习并重新设置一些更常见的功能。 我想执行一个简单的例子,我从PC(主端)发送8个字节,从ARM MCU(从端)接收8个字节。我正在使用C232HM MPSSE电缆从PC发送/接收数据。 MCU SPI Tx / Rx代码如下所示: #include "stm32h7xx.h"
static void InitializeMCO(void);
static void ConfigureHSI(void);
static void InitializeMasterTxSPI(void);
volatile uint8_t aTxBuffer[8] = {'S','T','M','3','2','O','u','t'};
volatile uint8_t aRxBuffer[8] = {'E','m','p','t','y','A','r','r'};
uint32_t aRxBuffPos;
uint32_t aTxBuffPos;
uint8_t rxCounter;
uint8_t txCounter;
void SPI1_IRQHandler(void);
int main()
{
aRxBuffPos = 0;
aTxBuffPos = 0;
rxCounter = 0;
txCounter = 0;
ConfigureHSI();
InitializeMCO();
InitializeMasterTxSPI();
while (1)
{
};
}
/* Initializes the MCU clock */
static void ConfigureHSI(void)
{
PWR->CR3 |= PWR_CR3_SCUEN;
PWR->D3CR |= (PWR_D3CR_VOS_1 | PWR_D3CR_VOS_0);
while ((PWR->D3CR & PWR_D3CR_VOSRDY) != PWR_D3CR_VOSRDY)
{
};
FLASH->ACR = FLASH_ACR_LATENCY_2WS;
RCC->CR |= RCC_CR_HSION;
while ((RCC->CR & RCC_CR_HSIRDY) != RCC_CR_HSIRDY)
{
};
RCC->PLLCKSELR = (4u << RCC_PLLCKSELR_DIVM1_Pos) |
(32u << RCC_PLLCKSELR_DIVM2_Pos) |
(32u << RCC_PLLCKSELR_DIVM3_Pos) |
RCC_PLLCKSELR_PLLSRC_HSI;
RCC->PLLCFGR = RCC_PLLCFGR_DIVR1EN |
RCC_PLLCFGR_DIVQ1EN |
RCC_PLLCFGR_DIVP1EN |
(2u << RCC_PLLCFGR_PLL1RGE_Pos) |
(1u << RCC_PLLCFGR_PLL1VCOSEL_Pos);
RCC->PLL1DIVR = ((2u - 1u) << RCC_PLL1DIVR_R1_Pos) |
((2u - 1u) << RCC_PLL1DIVR_Q1_Pos) |
((2u - 1u) << RCC_PLL1DIVR_P1_Pos) |
((50u - 1u) << RCC_PLL1DIVR_N1_Pos)
;
RCC->D1CFGR = RCC_D1CFGR_D1CPRE_DIV1;
RCC->D1CFGR = RCC_D1CFGR_HPRE_DIV2 | RCC_D1CFGR_D1PPRE_DIV2;
RCC->D2CFGR = RCC_D2CFGR_D2PPRE1_DIV2 | RCC_D2CFGR_D2PPRE2_DIV2;
RCC->D3CFGR = RCC_D3CFGR_D3PPRE_DIV2;
RCC->CR |= RCC_CR_PLL1ON;
while (!(RCC->CR & RCC_CR_PLLRDY))
{
};
RCC->CFGR |= (1u << 25);
RCC->CFGR |= RCC_CFGR_SW_PLL1;
while (!(RCC->CFGR & RCC_CFGR_SWS_PLL1))
{
};
}
/* Displays MCO on PC9 */
static void InitializeMCO(void)
{
RCC->CFGR |= RCC_CFGR_MCO2;
RCC->AHB4ENR &= ~RCC_AHB4ENR_GPIOCEN;
RCC->AHB4ENR |= RCC_AHB4ENR_GPIOCEN;
GPIOC->MODER &= ~GPIO_MODER_MODER9;
GPIOC->MODER |= GPIO_MODER_MODER9_1;
GPIOC->OTYPER &= ~GPIO_OTYPER_OT_9;
GPIOC->PUPDR &= ~GPIO_PUPDR_PUPDR9;
GPIOC->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR9;
GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR9;
GPIOC->AFR[0] &= ~GPIO_AFRL_AFRL0;
}
static void InitializeMasterTxSPI(void)
{
RCC->AHB4ENR |= RCC_AHB4ENR_GPIOAEN; // Enable usage of GPIOA
GPIOA->MODER &= ~GPIO_MODER_MODER5;
GPIOA->MODER |= GPIO_MODER_MODER5_1; // Alternate function for SPI1 SCK on PA5
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR5; // High Speed on PA5
GPIOA->AFR[0] |= (0x05 << 5 * 4); // AFRL selected AF5 (SPI1 SCK) for PA5
GPIOA->MODER &= ~GPIO_MODER_MODER6;
GPIOA->MODER |= GPIO_MODER_MODER6_1; // Alternate function for SPI1 MISO on PA6
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6; // High Speed on PA6
GPIOA->AFR[0] |= (0x05 << 6 * 4); // AFRL selected AF5 (SPI1 MISO) for PA6
GPIOA->MODER &= ~GPIO_MODER_MODER7;
GPIOA->MODER |= GPIO_MODER_MODER7_1; // Alternate function for SPI1 MOSI on PA7
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR7; // High Speed on PA7
GPIOA->AFR[0] |= (0x05 << 7 * 4); // AFRL selected AF5 (SPI1 MOSI) for PA7
GPIOA->MODER &= ~GPIO_MODER_MODER15;
GPIOA->MODER |= GPIO_MODER_MODER15_1; // Alternate function for SPI1 NSS on PA4
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR15; // High Speed on PA4
GPIOA->AFR[1] |= (0x05 << (15 - 8) * 4); // AFRL selected AF5 (SPI1 NSS) for PA4
GPIOA->PUPDR |= GPIO_PUPDR_PUPDR15; // Ensure all pull up pull down resistors are enabled
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR5; // Ensure all pull up pull down resistors are disabled
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR6; // Ensure all pull up pull down resistors are disabled
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR7; // Ensure all pull up pull down resistors are disabled
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
SPI1->CFG1 = (0u << SPI_CFG1_FTHLV_Pos) |
(7u << SPI_CFG1_DSIZE_Pos);
SPI1->CFG2 = 0;
//SPI1->CFG2 |= SPI_CFG2_LSBFRST;
//SPI1->CFG2 |= SPI_CFG2_CPHA;
//SPI1->CFG2 |= SPI_CFG2_CPOL;
//SPI1->CR2 = 8;
NVIC_SetPriority(SPI1_IRQn, 1);
NVIC_EnableIRQ(SPI1_IRQn);
//SPI1->IER |= SPI_IER_DXPIE;
SPI1->IER |= SPI_IER_RXPIE;
SPI1->IER |= SPI_IER_TXPIE;
SPI1->CR1 |= SPI_CR1_SPE;
}
void SPI1_IRQHandler(void)
{
if(SPI1->SR & SPI_SR_RXP)
{
//while(SPI1->SR & SPI_SR_RXP)
{
aRxBuffer[aRxBuffPos++] = *((__IO uint8_t *)&SPI1->RXDR);
//aRxBuffer[aRxBuffPos++] = *(volatile uint8_t *) SPI1->RXDR;
//aRxBuffer[aRxBuffPos++] = SPI1->RXDR;
}
}
if(SPI1->SR & SPI_SR_TXP)
{
//while(SPI1->SR & SPI_SR_TXP)
{
*(volatile uint8_t *) &(SPI1)->TXDR = aTxBuffer[aTxBuffPos++];
//*(volatile uint8_t *) &(SPI1)->TXDR = RxBuff[SPI_ByteCount++];
}
}
if (aTxBuffPos >= 8)
{
aTxBuffPos = 0;
txCounter++;
}
if (aRxBuffPos >= 8)
{
aRxBuffPos = 0;
rxCounter++;
}
} 代码是使用IAR Embedded Workbench编译的。 C SPI Tx / Rx代码如下所示:
- #include
- #include
- #include "libMPSSE_spi.h"
- void print_and_quit(char cstring[]) {
- printf("%sn", cstring);
- system("pause");
- exit(1);
- }
- int main(int argc, char **argv) {
- Init_libMPSSE();
- FT_STATUS status;
- FT_DEVICE_LIST_INFO_NODE channelInfo;
- FT_HANDLE handle;
- // check how many MPSSE channels are available
- uint32 channelCount = 0;
- status = SPI_GetNumChannels(&channelCount);
- if (status != FT_OK)
- print_and_quit("Error while checking the number of available MPSSE channels.");
- else if (channelCount < 1)
- print_and_quit("Error: no MPSSE channels are available.");
- printf("There are %d channels available.nn", channelCount);
- for (int i = 0; i < channelCount; i++) {
- status = SPI_GetChannelInfo(i, &channelInfo);
- if (status != FT_OK)
- print_and_quit("Error while getting details for an MPSSE channel.");
- printf("Channel number: %dn", i);
- printf("Description: %sn", channelInfo.Description);
- printf("Serial Number: %dn", channelInfo.SerialNumber);
- }
- // ask the user to select a channel
- uint32 channel = 0;
- //printf("nEnter a channel number to use: ");
- //scanf_s("%d", &channel);
- // open the MPSSE channel (get the handle for it)
- status = SPI_OpenChannel(channel, &handle);
- if (status != FT_OK)
- print_and_quit("Error while opening the MPSSE channel.");
- else
- printf("Channel openedn");
- ChannelConfig channelConfig;
- channelConfig.ClockRate = 4000000;
- channelConfig.configOptions = SPI_CONFIG_OPTION_MODE0 | SPI_CONFIG_OPTION_CS_DBUS3 | SPI_CONFIG_OPTION_CS_ACTIVELOW;
- channelConfig.LatencyTimer = 1;
- status = SPI_InitChannel(handle, &channelConfig);
- if (status != FT_OK)
- print_and_quit("Error while initializing the MPSSE channel.");
- else
- printf("Channel initializedn");
- uint8 tx_buffer[8] = { 'P' , 'C', 'S', 'P', 'I', 'O', 'u', 't', },
- rx_buffer[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
- uint32 transferCount = 0;
- uint32 options = SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES | SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE | SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE;
- //while (1)
- {
- status = SPI_ReadWrite(handle, rx_buffer, tx_buffer, 8, &transferCount, options);
- printf("tx = %c %c %c %c %c %c %c %c, rx = %c %c %c %c %c %c %c %cn", tx_buffer[0], tx_buffer[1], tx_buffer[2], tx_buffer[3], tx_buffer[4], tx_buffer[5], tx_buffer[6], tx_buffer[7],
- rx_buffer[0], rx_buffer[1], rx_buffer[2], rx_buffer[3], rx_buffer[4], rx_buffer[5], rx_buffer[6], rx_buffer[7]);
- Sleep(500);
- }
- system("pause");
- Cleanup_libMPSSE();
- return 0;
- }
复制代码
代码是使用Microsoft Visual Studio编译的。 一切正常。至少在PC方面我能够向MCU发送数据和从MCU接收数据,仔细调试后,我注意到只有PC到MCU的线路正常工作。MCU始终接收全零数据。 这是启动传输之前的调试器输出:
理想情况下,传输开始后应覆盖aRxBuffer的内容。 实际上,MCU正确地传输了所有数据,尽管它接收的是全零数据而不是实际发送的数据:
我做了各种故障排除尝试,例如: - 我用示波器探测了SCK / MISO / MOSI信号,它们看起来都是正确的,即导线或PCB走线没有物理问题。换句话说,有一个从C232HM到MCU的正确数字MOSI信号。
- 我在MCU和PC端都使用了所有时钟相位/极性组合,并且没有任何调整似乎在接收器侧产生任何数据(我可以破坏PC端接收的数据,尽管这是预期)。
- 如果我从C232HM断开MOSI电缆并将MCU侧的MOSI引脚连接到+ 3.3V电压轨,我的aRxBuffer缓冲区将填充0xFF。MCU侧存在一些接受响应,尽管它没有在CLK边缘执行。
有大神知道这是什么情况吗?
0
|
4个回答
|
|
|