大家好,
如果我在我的问题格式/清晰度上犯了一些错误,请在这里发表第一篇文章,因此深表歉意。
我正在使用 SPI HAL 库进行一些测试,尝试与另一个芯片进行
通信,一切都按预期进行,我可以成功发送字节并接收预期数据。
然而,有一个我似乎无法解释或克服的小问题。
STM32F072RB 复位后 SCK 信号立即保持高电平(暗示高空闲状态),但是我已将我的 SPI 设置为使用 MODE 0 进行通信,即低空闲状态,并在上升沿采样。这种高空闲状态导致第一个接收到的数据左移 1 位,因为在 SS 被断言后时钟执行的第一个转换是下降沿,指示数据在随后的上升沿发生变化。这之后的所有交易都是正确的。
这是不正确的行为,SCK 应始终处于低空闲状态。我曾尝试在将 GPIO 设置为备用功能引脚之前将其拉低,之后将其拉低,应用上拉/下拉电阻无济于事。(尽管我应该注意到,上拉/下拉电阻永远不会起作用,因为从芯片的输入端有一个上拉电阻!)。我的假设是从芯片上的上拉电阻干扰了 SS 信号,但我不确定为什么它只发生在启动时。
我想出了一个有点笨拙的修复方法,通过它我调用 SPI 传输而不断言 SS 信号。这会导致 SCK 在不发送任何数据的情况下循环,之后 SCK 正确地闲置为低电平,似乎无限期。请参阅下面的代码片段和逻辑分析器输出:
SPI GPIO 初始化(注释代码是对早期修复的尝试):
- void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
- {
- GPIO_InitTypeDef GPIO_InitStruct = {0};
- if(hspi->Instance==SPI2)
- {
- /* USER CODE BEGIN SPI2_MspInit 0 */
- /* USER CODE END SPI2_MspInit 0 */
- /* Peripheral clock enable */
- __HAL_RCC_SPI2_CLK_ENABLE();
- __HAL_RCC_GPIOB_CLK_ENABLE();
- /**SPI2 GPIO Configuration
- PB13 ------> SPI2_SCK
- PB14 ------> SPI2_MISO
- PB15 ------> SPI2_MOSI
- */
- GPIO_InitStruct.Pin = SPI2_MISO_Pin | SPI2_MOSI_Pin; //SPI2_SCK_Pin | SPI2_MOSI_Pin
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
- GPIO_InitStruct.Alternate = GPIO_AF0_SPI2;
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
- // HAL_GPIO_WritePin(GPIOB, SPI2_SCK_Pin, GPIO_PIN_RESET);
- // GPIO_InitStruct.Pin = SPI2_SCK_Pin;
- // GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
- // GPIO_InitStruct.Pull = GPIO_NOPULL;
- // GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
- // GPIO_InitStruct.Alternate = GPIO_AF0_SPI2;
- // HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
- // HAL_GPIO_WritePin(GPIOB, SPI2_SCK_Pin, GPIO_PIN_RESET);
- GPIO_InitStruct.Pin = SPI2_SCK_Pin;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
- GPIO_InitStruct.Alternate = GPIO_AF0_SPI2;
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
- /* USER CODE END SPI2_MspInit 1 */
- }
- }
SPI 参数和我对虚拟传输的简陋修复):
- static void MX_SPI2_Init(void)
- {
- /* USER CODE BEGIN SPI2_Init 0 */
- uint8_t temp_send[1] = {0x00};
- // init PA9 - to be used as CS
- GPIOA->ODR |= GPIO_ODR_9;
- GPIOA->MODER &= ~GPIO_MODER_MODER9_Msk;
- GPIOA->MODER |= GPIO_MODER_MODER9_0;
- GPIOA->OTYPER &= ~GPIO_OTYPER_OT_9;
- /* USER CODE END SPI2_Init 0 */
- /* USER CODE BEGIN SPI2_Init 1 */
- /* USER CODE END SPI2_Init 1 */
- /* SPI2 parameter configuration*/
- hspi2.Instance = SPI2;
- hspi2.Init.Mode = SPI_MODE_MASTER;
- hspi2.Init.Direction = SPI_DIRECTION_2LINES;
- hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
- hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
- hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
- hspi2.Init.NSS = SPI_NSS_SOFT;
- hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
- hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
- hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
- hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
- hspi2.Init.CRCPolynomial = 7;
- hspi2.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
- hspi2.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
- if (HAL_SPI_Init(&hspi2) != HAL_OK)
- {
- Error_Handler();
- }
- /* USER CODE BEGIN SPI2_Init 2 */
- /* I *think* there's some sort of bug with the way the HAL sets up the GPIO clock pin for use in SPI.
- * No matter what I do with the clock pin, even if I FORCE it low before assigning it as an alternate function, it always asserts itself during initialisation (giving the impression of a high idle state)
- * --> this has the adverse effect of putting aXiom 1 clock cycle ahead, hence everything comes out LS by 1 (this only happens on the first transaction)
- * My VERY jammy way of getting around this is to pretend to send a byte without asserting the CS pin, this somehow 'tricks' the clock into idling low without triggering aXiom
- * I don't like how this works, but it does...oh well!
- */
- HAL_SPI_Transmit(&hspi2, temp_send, sizeof(temp_send), 0);
- /* USER CODE END SPI2_Init 2 */
- }
显示高时钟空闲的逻辑波形(复位后的第一个事务):
显示低时钟空闲的逻辑波形(每个后续事务):
虽然我已经为我的问题提出了某种解决方案,但我更愿意有一个稍微更强大的解决方案,它不涉及“摇摆不定”的 SCK。所以我的问题是:
有谁知道一种方法可以确保 SCK 在启动时正确地处于低空闲状态?这是一个已知问题吗?
0