STM32F4:EEPROM 25LC256通过SPI进行管理

STM32F4:EEPROM 25LC256通过SPI进行管理,stm32,spi,eeprom,Stm32,Spi,Eeprom,我试图驾驶一辆STM32F469I-DISCO,但无法实现。 我曾尝试使用HALAPI基来创建自己的函数,但显然有些地方出了问题:我不知道是否在芯片上写入数据,因为我无法读取数据。让我再解释一下 所以我的芯片是一个DIP25LC256(DS在上面是你想要的)。EEPROM的引脚保持和WP与VCC(3.3V)相连。插脚CS连接至PH6(板上的ARD_D10)并由软件管理。插脚SI和插脚SO分别连接到PB15(ARD_D11)和PB14(ARD_D12),并具有正确的备用功能(GPIO_AF5_SP

我试图驾驶一辆STM32F469I-DISCO,但无法实现。 我曾尝试使用HALAPI基来创建自己的函数,但显然有些地方出了问题:我不知道是否在芯片上写入数据,因为我无法读取数据。让我再解释一下

所以我的芯片是一个DIP25LC256(DS在上面是你想要的)。EEPROM的引脚保持和WP与VCC(3.3V)相连。插脚CS连接至PH6(板上的ARD_D10)并由软件管理。插脚SI和插脚SO分别连接到PB15(ARD_D11)和PB14(ARD_D12),并具有正确的备用功能(GPIO_AF5_SPI2)。引脚SCK也连接到PD3(ADR_D13)

以下是我的SPI配置代码:

EEPROM_StatusTypeDef ConfigurationSPI2(SPI_HandleTypeDef *spi2Handle){

  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();

  GPIO_InitTypeDef  gpioInit;

  ////  SCK [PD3]
  gpioInit.Pin =    GPIO_PIN_3;
  gpioInit.Mode =   GPIO_MODE_AF_PP;
  gpioInit.Pull =   GPIO_PULLDOWN;
  gpioInit.Speed =  GPIO_SPEED_FREQ_HIGH;
  gpioInit.Alternate = GPIO_AF5_SPI2;

  HAL_GPIO_Init(GPIOD, &gpioInit);

  //// MOSI [PB15]
  gpioInit.Pin =    GPIO_PIN_15;
  gpioInit.Pull =   GPIO_PULLUP;
  HAL_GPIO_Init(GPIOB, &gpioInit);

  //// MISO [PB14]
  gpioInit.Pin =    GPIO_PIN_14;
  gpioInit.Pull =   GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &gpioInit);

  //// CS [PH6]
  gpioInit.Pin =    GPIO_PIN_6;
  gpioInit.Mode =   GPIO_MODE_OUTPUT_PP;
  gpioInit.Speed =  GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOH, &gpioInit);
  HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, GPIO_PIN_SET);

  //// SPI2

  __HAL_RCC_SPI2_CLK_ENABLE();

  spi2Handle->Instance = SPI2;

  spi2Handle->Init.Mode =               SPI_MODE_MASTER;
  spi2Handle->Init.Direction =          SPI_DIRECTION_2LINES;
  spi2Handle->Init.DataSize =           SPI_DATASIZE_8BIT;
  spi2Handle->Init.CLKPolarity =        SPI_POLARITY_LOW;
  spi2Handle->Init.CLKPhase =           SPI_PHASE_1EDGE;
  spi2Handle->Init.NSS =                SPI_NSS_SOFT;
  spi2Handle->Init.BaudRatePrescaler =  SPI_BAUDRATEPRESCALER_16;
  spi2Handle->Init.FirstBit =           SPI_FIRSTBIT_MSB;
  spi2Handle->Init.TIMode =             SPI_TIMODE_DISABLE;
  spi2Handle->Init.CRCCalculation =     SPI_CRCCALCULATION_DISABLE ;
  spi2Handle->Init.CRCPolynomial =      7;

  if(HAL_SPI_Init(spi2Handle) != HAL_OK){
      return EEPROM_ERROR;
  }

  return EEPROM_OK;
}
和两个函数,分别允许(理论上)写入和读取芯片:

写入功能:

EEPROM_StatusTypeDef WriteEEPROM(SPI_HandleTypeDef *spi2Handle, uint8_t *txBuffer, uint16_t size, uint16_t addr){

    uint8_t addrLow = addr & 0xFF;
    uint8_t addrHigh = (addr >> 8);

    uint8_t wrenInstruction = WREN_EEPROM; // Value : 0x06

    uint8_t buffer[32] = {WRITE_EEPROM, addrHigh, addrLow}; //Value : 0x02

    for(uint i = 0 ; i < size ; i++){
        buffer[3+i] = txBuffer[i];
    }

    HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, RESET);
    if(HAL_SPI_Transmit(spi2Handle, &wrenInstruction, 1, TIMEOUT_EEPROM) != HAL_OK){
        return EEPROM_ERROR;;
    }
    HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, SET);

    HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, RESET);
    if(HAL_SPI_Transmit(spi2Handle, buffer, (size + 3), TIMEOUT_EEPROM) != HAL_OK){
        return EEPROM_ERROR;
    }
    HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, SET);

    return EEPROM_OK;
}
EEPROM_StatusTypeDef ReadEEPROM(SPI_HandleTypeDef *spi2Handle, uint8_t *rxBuffer, uint16_t size, uint16_t addr){

    uint8_t addrLow = addr & 0xFF;
    uint8_t addrHigh = (addr >> 8);
    uint8_t txBuffer[3] = {READ_EEPROM, addrHigh, addrLow};

    HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, RESET);

    HAL_SPI_Transmit(spi2Handle, txBuffer, 3, TIMEOUT_EEPROM);

    HAL_SPI_Receive(spi2Handle, rxBuffer, size, TIMEOUT_EEPROM);    

    HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, SET);

    return EEPROM_OK;
}
我知道我的功能不是很“漂亮”,但这是第一次尝试。在我的主要工作中,我首先尝试将0x01地址处的数据“0x05”写入芯片,然后将该数据读回:

uint8_t bufferEEPROM[1] = {5};
uint8_t bufferEEPROM2[1] = {1};

WriteEEPROM(&spi2Handle, bufferEEPROM, 1, 0x01);
ReadEEPROM(&spi2Handle, bufferEEPROM2, 1, 0x01);
我有一个示波器,因为它不工作(使用STM Studio进行监控),所以我可视化了CLK和SI引脚,然后是CLK和so引脚(只能同时看到两个通道):

如您所见,第一张图片显示的是蓝色的CLK(黄色)和SI(或MOSI),我得到了所有预期数据:写启用指令,然后是指令。在地址之后,然后是数据

之后,Read函数启动。首先是读取指令和要获取数据的地址。最后8位应该是存储在地址(本例中为0x01)的数据。SI引脚上发生了一些事情,但我想这是因为HAL_SPI_Receive()函数实际上调用了HAL_SPI_TransmitReceive(),并将我的数组bufferEEPROM2作为参数(这就是为什么我们可以使用0b0000001)。这是因为我的SPI配置参数(全双工)

无论如何,理论上我应该在SO引脚上看到0b00000101,但正如你在第二张图片中看到的那样。。。。没什么

我试着改变gpioInit.Pull,以便在上拉和下拉时锁定,但没有改变。不完全是因为那是我最后一次尝试

问题是我不知道从哪里开始。我的传输似乎有效(但实际上有效吗?)。我的初始化有什么问题吗?实际上,我的主要问题是:为什么我没有从EEPROM接收任何数据


非常感谢

写入操作需要一些时间才能完成(您的数据表在第4页上显示为5毫秒),在此期间,除了读取状态外,不可能执行任何操作。尝试使用
RDSR(0x05)
opcode轮询状态寄存器,以确定它何时准备就绪(位0)。您还可以在发出
WREN
之前和之后检查状态(位1),以查看它是否成功。

因此问题现在已解决。以下是改进措施:

实际上有两个问题。第一个,当然也是最重要的一个,正如贝伦迪所说的,是时间问题。在我的写入功能中,我没有让EEPROM完成写入周期的时间(数据表上为5毫秒)。我在所有写函数的末尾添加了以下代码行:

HAL_Delay(10); //10 ms wait for the EEPROM to complete the write cycle
如果时间是预先设定的(理论上是5毫秒),延迟值可能会更小。但我没有在10毫秒以下进行测试。还有一件事。在示波器上,我也看到我的芯片选择在最后一个时钟边沿中间使用了<强>高>强。我不能说这是否也意味着一些问题,因为这是我首先通过在
halu Delay(10)
之前添加代码行解决的问题。我的所有SPI传输功能现在都以这种方式完成:

while(HAL_GPIO_ReadPin(CLK_PORT, CLK_PIN) == GPIO_PIN_SET){
}
HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_SET);
HAL_Delay(10);
这样我就有了正确的模式,我可以在EEPROM中写入并读回我写的内容

注:最后一件事让我更深入地理解了我对事件的误解:因为我的写函数不起作用,所以我专注于状态寄存器的写和读函数(为了一步一步地解决这个问题)。write函数也不起作用,事实上这是因为没有设置
WREN
位。我认为(错误的一个)写入状态寄存器的事实并不像写入内存的函数那样要求设置
WREN
。事实上,这也是必要的


谢谢你的帮助

不久前,我为STM32+SPI EEPROM编写了lib。STM技术支持部也对其进行了检查。目前,我在大约十个项目中使用这个库,效果很好。看一看