If anybody cares, I wrote some code to add the missing part about the SPI - LSB first mode...
The working mode is pretty simple: If the LSB bit first mode is not supported by SPI0 hardware, than we can do it by software... mirroring all the byte's before sending it to the HW and before passing the data from HW to the software.
You'll find the parts I changed and attached and you can find both the bcm2835.c and bcm2835.h with changes (you'll find the changes searching for my name... i put comments near each change ).
To apply them, you just need to place the modified files in the .src folder in the Mike's bcm2835 folder... please backup the orignal files first! Than you need to re-build the library with the well explained procedure on Mike's page.
I hope that I'll be excused by Mike about my really messy code... it's the first time that I edit someone else's code and I hope that will be added and fixed in next release of the library.
If you need anything, just ask.
=======================================================================================
Changed/added thing by Damiano Benedetti in BCM2835.c
=======================================================================================
//added by Damiano Benedetti
//enable or disable bit inversion in SPI
uint8_t spi_LSB_first = 0;
//added by Damiano Benedetti... here because i didn't know where to put it!
//declaration of a matrix of conversion to invert by sw the bit order
//each index of the array contains the mirrored value of its index number
uint8_t BitReverseTable[256] =
{
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
};
=======================================================================================
void bcm2835_spi_setBitOrder(uint8_t order)
{
// BCM2835_SPI_BIT_ORDER_MSBFIRST is the only one suported by SPI0
//Added by Damiano Benedetti
//MSB first is probably the only hardware supported mode... a software
//way to fix this is to invert the bit order before sending and receiveng data
//the easiest way is to use an array with all the data already stored
if (order == BCM2835_SPI_BIT_ORDER_MSBFIRST)
{spi_LSB_first=0;}
if (order == BCM2835_SPI_BIT_ORDER_LSBFIRST)
{spi_LSB_first=1;}
}
=======================================================================================
// Writes (and reads) a single byte to SPI
// SW mirroring for LSB first inserted and tested
uint8_t bcm2835_spi_transfer(uint8_t value)
{
volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4;
volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4;
// This is Polled transfer as per section 10.6.1
// BUG ALERT: what happens if we get interupted in this section, and someone else
// accesses a different peripheral?
// Clear TX and RX fifos
bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR);
// Set TA = 1
bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA);
// Maybe wait for TXD
while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD))
delayMicroseconds(10);
//added by Damiano Benedetti - software mirroring for SPI
if(spi_LSB_first)
{value = mirror_byte(value);}
// Write to FIFO, no barrier
bcm2835_peri_write_nb(fifo, value);
// Wait for DONE to be set
while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE))
delayMicroseconds(10);
// Read any byte that was sent back by the slave while we sere sending to it
uint32_t ret = bcm2835_peri_read_nb(fifo);
//added by Damiano Benedetti - software mirroring for SPI
if(spi_LSB_first)
{ret = mirror_byte(ret);}
// Set TA = 0, and also set the barrier
bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA);
return ret;
}
=======================================================================================
//function added by Damiano Benedetti for software mirroring
uint8_t mirror_byte (uint8_t data_to_be_mirrored)
{
uint8_t mirrored;
mirrored = BitReverseTable[data_to_be_mirrored];
return mirrored;
}
=======================================================================================
// Writes (and reads) an number of bytes to SPI
// SW mirroring for LSB first inserted but not tested
void bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len)
{
volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4;
volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4;
// This is Polled transfer as per section 10.6.1
// BUG ALERT: what happens if we get interupted in this section, and someone else
// accesses a different peripheral?
// Clear TX and RX fifos
bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR);
// Set TA = 1
bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA);
uint32_t i;
for (i = 0; i < len; i++)
{
// Maybe wait for TXD
while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD))
delayMicroseconds(10);
//added by Damiano Benedetti - software mirroring for SPI
if(spi_LSB_first)
{tbuf[i] = mirror_byte(tbuf[i]);}
// Write to FIFO, no barrier
bcm2835_peri_write_nb(fifo, tbuf[i]);
// Wait for RXD
while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD))
delayMicroseconds(10);
// then read the data byte
rbuf[i] = bcm2835_peri_read_nb(fifo);
//added by Damiano Benedetti - software mirroring for SPI
if(spi_LSB_first)
{rbuf[i] = mirror_byte(rbuf[i]);}
}
// Wait for DONE to be set
while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE))
delayMicroseconds(10);
// Set TA = 0, and also set the barrier
bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA);
}
=======================================================================================
// Writes an number of bytes to SPI
// SW mirroring for LSB first inserted but not tested
void bcm2835_spi_writenb(char* tbuf, uint32_t len)
{
volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4;
volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4;
// This is Polled transfer as per section 10.6.1
// BUG ALERT: what happens if we get interupted in this section, and someone else
// accesses a different peripheral?
// Clear TX and RX fifos
bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR);
// Set TA = 1
bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA);
uint32_t i;
for (i = 0; i < len; i++)
{
// Maybe wait for TXD
while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD))
;
//added by Damiano Benedetti - software mirroring for SPI
if(spi_LSB_first)
{tbuf[i] = mirror_byte(tbuf[i]);}
// Write to FIFO, no barrier
bcm2835_peri_write_nb(fifo, tbuf[i]);
}
// Wait for DONE to be set
while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE))
;
// Set TA = 0, and also set the barrier
bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA);
}
=======================================================================================
Changed/added thing by Damiano Benedetti in BCM2835.h
=======================================================================================
///Added by Damiano Benedetti: Mirrors the given byte.
/// Receive the data to be mirrored data and return the mirrored data
extern uint8_t mirror_byte (uint8_t data_to_be_mirrored);
=======================================================================================