Here is my basic setup. I am using the photon2 to program an AT28C256 EEPROM. Given its address and data lines I am using two MCP27S17 GPIO extenders that I can communicate to via SPI rather than the traditional ones most use which is slower I2C based.
When programming the EEPROM I need to take advantage of the page write capability so that it doesn't take 20 minutes to program. Haha. Basically I need to setup the address and data lines, then toggle the WE pin and then move on to the next address and data and repeat the process such that these writes don't take longer than 150 microseconds between each write. A page is 64 bytes long. Once I have written 64 bytes (the lower 7 address lines) I pause for slightly more than 10 milliseconds to wait for the page write to occur.
Note that any delay of greater than 150 microseconds between writes will trigger the page write process. So when I am doing my 64 byte chunks my timing is critical that I get all my wok done in under 150 microseconds.
Seems like something a MCU that is close to bare metal should handle. However I am running into difficulty as there appears to be random spots where the timing from one byte write to the next is delayed wich will trigger the page write too soon.
I am using a DLA to look at the timing and here are some screen shots showing what I am seeing. Note the top row is just a GPIO I am toggling to measure the total time to write all 64 bytes, the middle row is the actual SCK line of the SPI bus which is running at 12Mhz, and the 3rd row is the WE line to the EEPROM being toggled.
The first shot shows a capture and the all look really good
However, as you zoom in you can see that certain page writes will trigger early.
Here is the one page write with a timing delay.
And here is another that is perfect.
Regarding my code. I use
SYSTEM_MODE(MANUAL)
SYSTEM_THREAD(DISABLED)
Normally I will be getting data to burn to EEPROM via BLE and I won't do the burning process until all is received, however, in this test case, I am not enabling any BLE or Serial.
I'm just in this loop
void EEPROM_AT28C256::programEEPROM() {
digitalWriteFast(ROM_PROG_L, LOW); // take control of the EEPROM
driveAddressBus();
driveDataBus();
digitalWrite(OE_L, HIGH);
digitalWrite(WE_L, HIGH);
uint16_t address = 0;
for (uint16_t pageCount = 0; pageCount < sizeof(data) / 64; pageCount++) {
address = pageCount * 64;
digitalWriteFast(BE_L, LOW);
for (int i = address; i < address + 64; i++) {
setAddress(i);
setData(data[address]);
digitalWriteFast(WE_L, LOW);
digitalWriteFast(WE_L, HIGH);
}
digitalWriteFast(BE_L, HIGH);
delay(20); //
}
digitalWriteFast(ROM_PROG_L, HIGH); // Give control back to 6502
}
Here is my code that actually uses the SPI bus.
void EEPROM_AT28C256::writeRegister(uint8_t cs, uint8_t reg, uint8_t value) {
SPI.beginTransaction();
digitalWriteFast(cs, LOW); // Select the MCP23S17
SPI.transfer(WRITE_CMD); // Send write command
SPI.transfer(reg); // Send register address
SPI.transfer(value); // Send value
digitalWriteFast(cs, HIGH); // Deselect the MCP23S17
SPI.endTransaction();
};
My tendency is to want to disable all interrupts when doing the inner loop page write, but I believe that would break the SPI interface from working properly.
Any thoughts or hints on how I can get this to be consistent?