I'm trying to handle AT45DB161D SPI flash memory using the following code and could not read status/ID info correctly.
The test code read only status register and device ID (read/write data block is not implemented yet).
The read value from this test code resulted 0xFF, not expected value.
However, the same code worked as expected with FEZ Domino.
As I don't have oscilloscope, I could not narrow down the issue. Is there any advice for more investigation?
Test environments:
- Firmware: 4.1.0.3
- Host PC OS: Windows 7
- Change clock rate lower/higher than 1000Khz
- Change SPI mode to 3 (Clock_IdleState = true, Clock_Edge = false)
- Specify ChipSelect_Port in "SPI.Configuration". AS this resulted NG even with FEZ Domino, it seems AT45DB161D require CS active during command send and result acquisition period
- Insert wait (1ms) between CS active and start transaction
- Change jumper wire of SCK
- Power supply from external power jack
using System.Threading; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using SecretLabs.NETMF.Hardware.Netduino; /* ------------------------------------------- * Pin assignment Netduino <--> AT45DB161D * CS D8 -- 4 Pull-up with 10k ohm R * RESET D9 -- 3 Pull-down with 10k ohm R * MOSI D11 -- 1 * MISO D12 -- 8 * SCK D13 -- 2 --------------------------------------------*/ namespace NetSpiFlash { public class Program { public static void Main() { OutputPort csPin = new OutputPort(Pins.GPIO_PIN_D8, true); OutputPort resetPin = new OutputPort(Pins.GPIO_PIN_D9, true); SPI.Configuration config = new SPI.Configuration( Cpu.Pin.GPIO_NONE, // ChipSelect_Port. Not connected to the device false, // ChipSelect_ActiveState : active low 0, // ChipSelect_SetupTime 0, // ChipSelect_HoldTime false, // Clock_IdleState : the idle state of the clock is low true, // Data is sampled on the SPI clock riging edge (Mode 0) 1000, // Clock_Rate in KHz SPI.SPI_module.SPI1 // SPI_mod : D11 MOSI, D12 MISO, D13 SCK ); SPI spi1 = new SPI(config); AT45DB161D SpiFlash = new AT45DB161D(spi1, csPin, resetPin); byte status; while (true) { status = SpiFlash.ReadStatusRegister(); Debug.Print("Status Reg:" + status.ToString()); SpiFlash.ReadManufacturerAndDeviceID(); Debug.Print("Manufacturer ID:" + SpiFlash.Manufacturer.ToString()); Debug.Print("Device ID:" + SpiFlash.Device[0].ToString()); Thread.Sleep(1000); } } } public class AT45DB161D { // AT45DB161D_Commands private const byte STATUS_REGISTER_READ = 0xD7; private const byte READ_MANUFACTURER_AND_DEVICE_ID = 0x9F; // Chip Select value private const bool CS_INACTIVE = true; private const bool CS_ACTIVE = false; // SPI read/write data private byte[] writeBuffer = new byte[1]; private byte[] readBuffer = new byte[1]; private byte[] dummy = { 0 }; // Device ID feild public byte Manufacturer; public byte[] Device = new byte[2]; public byte ExtendedInfoLength; private SPI spi; private OutputPort cs; /// <summary> /// Constructor for Atmel AT45DB161D data flash /// </summary> public AT45DB161D(SPI spiMod, OutputPort csPin, OutputPort resetPin) { spi = spiMod; cs = csPin; cs.Write(CS_INACTIVE); // Reset AT45DB161D chip resetPin.Write(false); Thread.Sleep(10); resetPin.Write(true); } public byte ReadStatusRegister() { cs.Write(CS_ACTIVE); //Thread.Sleep(1); // Send status read command SPIWriteByte(STATUS_REGISTER_READ); byte status = SPIReadByte(); cs.Write(CS_INACTIVE); return status; } public void ReadManufacturerAndDeviceID() { cs.Write(CS_ACTIVE); //Thread.Sleep(1); // Send status read command SPIWriteByte(READ_MANUFACTURER_AND_DEVICE_ID); // Read Manufacturer ID (1FH, 31) Manufacturer = SPIReadByte(); // Read Device ID (Part 1) (26H, 38) Device[0] = SPIReadByte(); // Read Device ID (Part 2) (00H) Device[1] = SPIReadByte(); // Read Extended Device Information String Length (00H) ExtendedInfoLength = SPIReadByte(); cs.Write(CS_INACTIVE); } private void SPIWriteByte(byte B) { writeBuffer[0] = b; spi.Write(writeBuffer); } private byte SPIReadByte() { spi.WriteRead(dummy, readBuffer); return readBuffer[0]; } } }