1
\$\begingroup\$

EDIT: For those who tried to help or have found this question via google, I managed to solve this issue just by adding a 1uF ceramic bypass capacitor to the breadboard. Thanks for the answers.

I'm trying to program a AT28C64B with an STM32(running at 168MHz in case it's relevant). I have done something similar using 32K parallel SRAM chips so I assumed I could use some existing code by taking the EEPROM's required delays into account.However I can't write anything to the chip and I consistently read the same wrong values. Here's the code, I know it's a little messy but I'll tidy it up once it works.

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART3_UART_Init();
  MX_USB_OTG_FS_PCD_Init();

  /* Initialize interrupts */
  MX_NVIC_Init();
  /* USER CODE BEGIN 2 */
  int delayconst = 500;
  //int limit =sizeof(values)/sizeof(uint8_t);
  int limit = 15;
  setvbuf(stdin, NULL, _IONBF, 0);//disable buffers on stdin and stdout
  setvbuf(stdout, NULL, _IONBF, 0);
  __HAL_UART_ENABLE_IT(&huart3, UART_IT_RXNE);//enable receive interrupt
  //
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  /*
   * 28C64B programmer, 8192 addresses 0-8191
   * PB[0-7] -> IO[1-8]
   * PB[8-15] -> A[0-7]
   * PE[2-6] -> A[8-12]
   * PC8 -> WE high by default
   * PC9 -> OE
   * PC10 -> CE high by default
   * 
   */
  while (1)
  {

      uint8_t data;
      int but = 0;
      int errors = 0;

      printf("Press user button to program EEPROM\n");
      while(but == 0){
                  but = HAL_GPIO_ReadPin(USER_Btn_GPIO_Port, USER_Btn_Pin);
      }
      but = 0;
      printf("Programming EEPROM\n");

      GPIOB->MODER = (GPIOB->MODER & ~0xFFFF) | 0b0101010101010101; //make PB0-7 outputs

      HAL_GPIO_WritePin(GPIOC, OE_Pin, GPIO_PIN_SET);//disable OE before writing data

      for(uint8_t address = 0; address < limit;  ++address){
          HAL_GPIO_WritePin(GPIOC, WE_Pin, GPIO_PIN_SET);//disable WE before wiritng addresses+data

          GPIOB->ODR = (GPIOB->ODR & ~(0xFFFF)) | ((address & 0xFF)<<8) | values[address]; //first 8 address bits to PB8-15, data to pb-7
          GPIOE->ODR = (GPIOE->ODR & ~(0b11111<<2)) | ((address &0x1F00)>>6);//upper 5 address bytes to pe2-6
          for (volatile int i=0; i!=delayconst; i++);//"1us" delay
          HAL_GPIO_WritePin(GPIOC, CE_Pin, GPIO_PIN_RESET);//enable CE after address and data are set
          HAL_GPIO_WritePin(GPIOC, WE_Pin, GPIO_PIN_RESET);
          for (volatile int i=0; i!=delayconst; i++);//"1us" delay
          HAL_GPIO_WritePin(GPIOC, WE_Pin, GPIO_PIN_SET);
          HAL_GPIO_WritePin(GPIOC, CE_Pin, GPIO_PIN_SET);

          HAL_Delay(10);//10ms write cycle

          }

          printf("EEPROM programmed, verify?\n\r");//

          while(but == 0){
              but = HAL_GPIO_ReadPin(USER_Btn_GPIO_Port, USER_Btn_Pin);
          }
          but = 0;

          GPIOB->MODER &=  ~0xFFFF; //make PB0-7 inputs by setting first 16 bits of MODER to 0
          HAL_GPIO_WritePin(GPIOC, OE_Pin, GPIO_PIN_RESET);//chip in standby but prepared for read mode
          HAL_GPIO_WritePin(GPIOC, WE_Pin, GPIO_PIN_SET);

          for(int address = 0; address < limit;  ++address){
              GPIOB->ODR = (GPIOB->ODR & ~(0xFF<<8)) | ((address & 0xFF)<<8); //first 8 address bits to PB8-15
              GPIOE->ODR = (GPIOE->ODR & ~(0b11111<<2)) | ((address &0x1F00)>>6);//upper 5 address bytes to pe2-6

              for (volatile int i=0; i!=delayconst; i++);//"1us" delay
              HAL_GPIO_WritePin(GPIOC, CE_Pin, GPIO_PIN_RESET);//activate chip and read data
              for (volatile int i=0; i!=delayconst; i++);//"1us" delay

              data = (GPIOB->IDR & 0xFF);
              if(data != values[address]){
                  ++errors;
                  printf("Found error at %X. Expected %X, got %X\n\r", address, values[address], data);
              }
              HAL_GPIO_WritePin(GPIOC, CE_Pin, GPIO_PIN_SET);
              for (volatile int i=0; i!=delayconst; i++);//"1us" delay


          }
          printf("Found %i errors. Waiting for button.", errors);
          while(but == 0){
              but = HAL_GPIO_ReadPin(USER_Btn_GPIO_Port, USER_Btn_Pin);
          }
          but = 0;
}



    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

  /* USER CODE END 3 */
}

To clarify things, PB0-7 are connected to IO0-7, PB8-15 are connected to A0-7, PE2-6 are connected to A8-12 and PC8,PC9 and PC10 are connected to WE, OE and CE respectively. The chip is supplied with 5V and directly connected to 5V-tolerant GPIO pins. I'm sure the parts with the GPIO registers are not the problem because I used them with SRAM chips connected similarly and had no problems.

The first for loop(which writes data to the chip) looks ugly because I tried to replicate the write waveforms in the datasheet but it didn't help. I used a for loop with a volatile-declared index to create delays in the range of microseconds and experimented with many values of delayconst between 500 and 500000 to change the delay's duration but I always read the same wrong values every time. I'm starting to think the write protection feature is active somehow. Does anyone have an idea what the problem might be?

\$\endgroup\$
3
  • \$\begingroup\$ I have not read the datasheet but these devices often have to have an unlock code written to them prior to writing data. \$\endgroup\$ Commented Apr 5, 2021 at 16:05
  • \$\begingroup\$ I used my Willem programmer to test this and it could write without any issues, I also tried the tried disabling the protection using the information in the datasheet but it didn't change anything. Since my programmer can write without issues, I think the issue is with my code. \$\endgroup\$
    – 08d09
    Commented Apr 5, 2021 at 17:17
  • \$\begingroup\$ @08d09 Please do not provide the solution in the question. Instead, revert and post an own answer, which you should mark as "accepted" afterwards. This site and its visitors live from these green markers and actual answers, it is not a forum. \$\endgroup\$ Commented Dec 8, 2023 at 7:12

1 Answer 1

1
\$\begingroup\$

Initially you did not say which device exactly you are using, so I looked up this one by Microchip to try to help.

Well, you already mentioned it in your question, the data protection might be enabled. You can check this by comparing the values read from the device. If you cannot change a bit, and it reads a byte always the same, the device is protected. The sequence to disable the protection is in the data sheet.

You need to be aware of the "polling operation" during the write (D7 is inverted, D6 is alternating on each read, D5 to D0 are to be ignored). However, you can "jump over" it with some delay, as you try to do.

EDIT

The polling operation is described in the data sheet. In general, it works like this:

  • During the write cycle (maximum 10ms says the data sheet) you read the last byte written (the highest address on multi-byte page writes).
  • The bit value on D7 is inverted to the value to be written.
  • The bit value on D6 alternates between 0 and 1 on each read.
  • Ignore all other bits read.
  • Repeat as long as D7 is inverted.
  • As soon as you read the byte you wrote, the cycle has finished.

The data sheet also mentions the hardware protection:

Hardware features protect against inadvertent writes to the AT28C64B in the following ways:

  • (a) VCC sense – if VCC is below 3.8 V (typical), the write function is inhibited;
  • (b) VCC power-on delay – once VCC has reached 3.8 V, the device will automatically time out 5 ms (typical) before allowing a write;
  • (c) write inhibit – holding any one of OE low, CE high, or WE high inhibits write cycles; and
  • (d) noise filter – pulses of less than 15 ns (typical) on the WE or CE inputs will not initiate a write cycle.

You might like to check that you have considered all of these conditions.

Chapter 4.6.2 should be a must-read, too.

\$\endgroup\$
5
  • \$\begingroup\$ The eeprom is most likely a 5V device. The STM32 is 3V3. Do you have level translators? Many cmos SRAM will work on 3V3, 5V eeproms will probably refuse. \$\endgroup\$
    – Kartman
    Commented Apr 5, 2021 at 11:05
  • \$\begingroup\$ @Kartman The question in this comment should go to the OP. ;-) Anyway, the hint on the supply voltage is valuable, but the OP did not tell us the specific device. \$\endgroup\$ Commented Apr 5, 2021 at 12:26
  • \$\begingroup\$ @busybee. I agree. Sorry finger trouble on a mobile device! \$\endgroup\$
    – Kartman
    Commented Apr 5, 2021 at 12:29
  • \$\begingroup\$ @Kartman The pins I use are 5V tolerant according to the datasheet so I didn't use any level translators, The EEPROM is supplied with 5V. I could use my SRAM(UM61256AK) chips with both 3.3V and 5V without issues. \$\endgroup\$
    – 08d09
    Commented Apr 5, 2021 at 17:21
  • \$\begingroup\$ @thebusybee I tried writing to the chip with a Willem programmer and it could write without any problems so data protection doesn't seem to be turned on(the programmer's software doesn't have an option to turn it on or off). I also tried applying the disable sequence but that also did not work. Could you please explain how polling works? i have a 10ms delay for the write cycle, should increasing that just skip over polling? \$\endgroup\$
    – 08d09
    Commented Apr 5, 2021 at 17:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.