STM32F4:通过SPI管理EEPROM 25LC256

时间:2017-04-11 20:37:58

标签: stm32 spi eeprom

我正在尝试使用STM32F469I-DISCO驱动EEPROM Chip 25LC256但无法实现它。 我试图用HAL API基础创建自己的函数,但显然有些错误:我不知道我是否在芯片上写入数据,因为我无法读取它。让我解释一下。

所以我的芯片是DIP 25LC256(你希望DS在上面)。 PIN保持和EEPROM的WP连接到VCC(3.3V)。 PIN CS连接到PH6(板载ARD_D10)并由软件管理。 PIN SI和PIN SO分别连接到具有右交替功能的PB15(ARD_D11)和PB14(ARD_D12)(GPIO_AF5_SPI2)。 PIN 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;
}

两个函数分别允许(和理论上)WRITE和READ进入芯片:

写功能:

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 PIN,然后显示CLK和SO PIN(同时只能看到两个通道):

Monitoring of CLK (Yellow) and SI (Blue)

Monitoring of CLK (Yellow) and SO (Blue)

正如您所看到的,第一张图片显示蓝色的CLK(黄色)和SI(或MOSI),我有所需的所有数据: WRite ENable 指令然后 WRITE 指令。在 ADDRESS 之后, DATA

之后,读取功能启动。首先是 READ 指令和 ADDRESS ,我想要获取数据。最后8位应该是存储在地址中的数据(在这种情况下为0x01)。在SI PIN上发生了一些事情,但我想这是因为HAL_SPI_Receive()函数实际上使用我的数组 bufferEEPROM2 作为参数调用 HAL_SPI_TransmitReceive()(这就是为什么我们可以选择0b00000001)。因此,这是因为我的SPI配置参数(全双工)。

无论如何,理论上我应该在SO PIN上看到 0b00000101 ,但你可以在第二张图片中看到....没有。

我试图在PULLUP和PULLDOWN上更改gpioInit.Pull以获取SO PIN但没有任何改变。 NOPULL是因为这是我尝试过的最后一件事。

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

非常感谢!

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:0)

所以问题现在解决了。以下是改进:

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

HAL_Delay(10); //10 ms wait for the EEPROM to complete the write cycle

延迟值可能会更少,我认为如果时间是有意义的(理论上为5毫秒)。虽然我没有在10毫秒以下测试。另一件事。在示波器中,我还看到我的芯片选择曾经在我的最后一个时钟边缘中间 HIGH 。我不知道这是否也意味着一些问题,因为我首先通过在HAl_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中写入并回读我写的内容。

NB:最后一件事让我更深入地了解了我对事件的误解:由于我的写功能不起作用,我专注于STATUS REGISTER写入和读取功能(为了逐步解决这个问题) 。写函数也没有工作,实际上是因为WREN位没有设置。我虽然(错误的一个)认为写入状态寄存器的事实并没有要求将WREN设置为内存要求的WRITE函数。实际上,这也是必要的。

感谢您的帮助!