I'm trying to interface with a Winbond W25Q64BV flash chip via SPI.
I started off by testing it on Arduino (target is a Raspberry) as I found a few implementations
before I got started. Most notably this instructable and this project on Google code.
The instructable gets the 'jedec' information like this:
Looking at the code from the instructable, the implementation to get the jedec information
void _get_jedec_id(byte *b1, byte *b2, byte *b3) {
digitalWrite(SS, HIGH);
digitalWrite(SS, LOW);
SPI.transfer(WB_JEDEC_ID);
*b1 = SPI.transfer(0); // manufacturer id
*b2 = SPI.transfer(0); // memory type
*b3 = SPI.transfer(0); // capacity
digitalWrite(SS, HIGH);
not_busy();
}
The project on Google code defined multiple requests for each piece of information,
but the idea is basically the same, for example getting the manufacturer id:
uint8_t winbondFlashClass::readManufacturer()
{
uint8_t c;
select();
transfer(R_JEDEC_ID);
c = transfer(0x00);
transfer(0x00);
transfer(0x00);
deselect();
return c;
}
After confirming this worked with the Arduino I wanted to port it to run on a Raspberry.
I enabled the SPI and confirmed the interface was available (method described here).
I installed the BCM2835 C library on the Raspberry (wheezy) as described here
Which is basically:
tar zxvf bcm2835-1.xx.tar.gz
cd bcm2835-1.xx
./configure
make
sudo make check
sudo make install
I wrote a little test application in C:
#include <bcm2835.h>
#include <stdio.h>
void main()
{
printf("START");
bcm2835_spi_begin();
//This all the code required to explain my problem
}
It compiled, was able to execute it (as root of course)
and it ran and completed without throwing any exceptions.
It did not however output anything, not even the text "START".
But if I remove the line bcm2835_spi_begin();
it does output "START".
I can't explain it and I'm not a C guy so I started looking at Python.
Using py-spidev, which is 'somewhat' documented here,
I started porting the code from the Arduino samples:
import spidev
import time
WB_ZERO = 0x00
WB_WRITE_ENABLE = 0x06
WB_WRITE_DISABLE = 0x04
WB_CHIP_ERASE = 0xC7
WB_READ_STATUS_REGISTER_1 = 0x05
WB_READ_STATUS_REGISTER_2 = 0x35
WB_READ_DATA = 0x03
WB_READ_PAGE_PROGRAM = 0x02
WB_JEDEC_ID = 0x9F
def connect(bus = 0, device = 0):
spi = spidev.SpiDev(bus, device)
spi.open(bus, device)
return spi
def configure(spi, max_speed_hz = 1953125, mode = 0, bits_per_word = 8):
spi.max_speed_hz = max_speed_hz
spi.mode = mode
spi.bits_per_word = bits_per_word
def print_configuration(spi):
print "max_speed_hz: %s" % spi.max_speed_hz
print "mode: %s" % spi.mode
print "bits_per_word: %s" % spi.bits_per_word
def cs_toggle_high_low(spi):
spi.cshigh = True;
spi.cshigh = False;
def cs_toggle_low_high(spi):
spi.cshigh = False;
spi.cshigh = True;
def cs_low(spi):
spi.cshigh = False;
def cs_high(spi):
spi.cshigh = True;
def transfer(spi, byte):
return spi.xfer([byte])[0]
def wait_for_device(spi):
transfer(spi, WB_READ_STATUS_REGISTER_1)
while(transfer(spi, WB_ZERO) == 1):
print ".",
def get_jedec_id(spi):
cs_toggle_high_low(spi)
transfer(spi, WB_JEDEC_ID)
manufacturer_id = transfer(spi, WB_ZERO)
memory_type = transfer(spi, WB_ZERO)
capacity = transfer(spi, WB_ZERO)
cs_high(spi);
wait_for_device(spi)
return (manufacturer_id, memory_type, capacity)
And then I used it as follows:
spi = connect()
configure(spi)
print_configuration(spi)
print get_jedec_id(spi)
With the cs_toggle_high_low
function I'm trying to simulate the calls
to digitalWrite
in the original code, but I honestly do not know if
it's the same,
although if I don't call cs_toggle_high_low
I always get 0x00 data.
The problem is, that I receive 0xFF for all 3 values when the flash chip is connected to the SPI bus
(whereas I receive 0x00, 0x00, 0x00 if it is not connected or I don't toggle).
So I'm wondering why the code using the BCM2835 library doesn't work (but doesn't throw errors either)
And what I might be doing wrong in the Python version.
Or basically, how I can interface the Raspberry with the flash chip successfully.