|
|
ringram2077
Expert Boarder |
|
2006/12/18 16:52 |
|
Bit Operation Problem
Hi If you haven't noticed already I am a newbie with the LM3S811 Eval Board as well as the RealView Compiler. I am trying to create a software spi interface(yes, I know there is a hareware SSI that can do this). The code is straight forward but I can't figure out how to code the bit specific operations needed to make it work. Here is the code:
| Code: | //Basic SPI send and receive
unsigned char spi_comm(unsigned char outgoing_byte)
{
unsigned char incoming_byte, x;
for(x = 0 ; x < 8 ; x++)
{
//SCL = 0; //Toggle the SPI clock
GPIOPinWrite(GPIO_PORTA_BASE, SSI_CLK, 0);
SSI_TX = outgoing_byte.7; //Put bit on SPI data bus
outgoing_byte <<= 1; //Rotate byte 1 to the left
//SCL = 1;
GPIOPinWrite(GPIO_PORTA_BASE, SSI_CLK, SSI_CLK);
incoming_byte <<= 1; //Rotate byte 1 to the left
//incoming_byte.0 = SDO; //Read bit on SPI data bus
incoming_byte.0 = GPIOPinRead(GPIO_PORTA_BASE, SSI_RX);
}
return(incoming_byte);
|
The first question concerns SSI_TX = outgoing_byte.7 . SSI_TX is defined as GPIO_PIN_2. I just don't know how to make this work. The second question concerns incoming_byte.0 = GPIOPinRead(GPIO_PORTA_BASE, SSI_RX); SSI_RX is defined as GPIO_PIN_3 .
I know you gurus can help me sort this out.
Thanks!
login or register to reply
|
|
|
orinem
Expert Boarder |
|
2006/12/19 01:48 |
|
Re:Bit Operation Problem
Here is some working SPI bit-banging code. Capable of up to 32 bits at once... see the comment. The ordering of setting DOUT, reading DIN, toggling the clock and the delays is quite critical depending on propagation delays in the SPI device you are talking to. The following does work with the device in question which doesn't seem to fit any configuration of the hardware SPI. I tuned the delays using a TDS210 'scope which reported the 2.1uS period when running the '811 at 40MHz.
| Code: |
#define MS5534_SCLK GPIO_PIN_2
#define MS5534_DOUT GPIO_PIN_4
#define MS5534_DIN GPIO_PIN_5
//
// MS5534Delay - a somewhat predictable delay
//
#if defined(gcc)
static void __attribute__((naked))
MS5534Delay(unsigned long ulCount)
{
__asm(" subs r0, #1n"
" bne MS5534Delayn"
" bx lr");
}
#endif
#if defined(rvmdk) || defined(__ARMCC_VERSION)
__asm void MS5534Delay(unsigned long ulCount)
{
subs r0, #1;
bne MS5534Delay;
bx lr;
}
#endif
//
// Send/Receive up to 32 bits to/from the MS5534
//
// Bits to be sent are left adjusted
//
// Reads a bit from the MS5534's DOUT pin, for each bit sent,
// whether it means anything or not! Bits of interest must
// be shifted and masked out of the return value.
//
// Note 500kHz clock max for the MS5534
//
long
MS5534Send(long bits, int nBits)
{
long result = 0;
// Output first bit and ensure SCLK is low.
// Note we do an if/else to avoid glitching the line
if ( bits < 0 )
{
HWREG(GPIO_PORTA_BASE + (GPIO_O_DATA + ((MS5534_DIN | MS5534_SCLK) << 2))) = MS5534_DIN;
}
else
{
HWREG(GPIO_PORTA_BASE + (GPIO_O_DATA + ((MS5534_DIN | MS5534_SCLK) << 2))) = 0;
}
// This loop takes a minimum of 4.5 uS with the CPU running at 6MHz
// with the SCLK high being about 1.7 uS, or put another way,
// at least 10 CPU clocks high and 17 CPU clocks low.
//
// 40MHz: Period is 2.1 uS with MS5534Delays of 7 and 10
do {
// MS5534Delay(1); // For 20MHz CPU clock
MS5534Delay(7); // For 40MHz CPU clock
// Set SCLK high
HWREG(GPIO_PORTA_BASE + (GPIO_O_DATA + (MS5534_SCLK << 2))) = MS5534_SCLK;
// MS5534Delay(2); // For 20MHz CPU clock
MS5534Delay(10); // For 40MHz CPU clock
result <<= 1;
bits <<= 1;
--nBits;
// Output the next bit along with setting SCLK low
if ( bits < 0 )
{
HWREG(GPIO_PORTA_BASE + (GPIO_O_DATA + ((MS5534_DIN | MS5534_SCLK) << 2))) = MS5534_DIN;
}
else
{
HWREG(GPIO_PORTA_BASE + (GPIO_O_DATA + ((MS5534_DIN | MS5534_SCLK) << 2))) = 0;
}
// Read the next bit on the falling edge of SCLK
if ( HWREG(GPIO_PORTA_BASE + (GPIO_O_DATA + (MS5534_DOUT << 2))) & MS5534_DOUT )
{
result |= 1;
}
} while ( nBits );
return result;
}
|
Enjoy, Orin.
login or register to reply
|
|
|
ringram2077
Expert Boarder |
|
2006/12/19 07:46 |
|
Re:Bit Operation Problem
Thanks for the code. I do have a question as to how it works. Looks like you would pass the routine a number to send to the device (bits) and a count for the number of bits to send (nbits). Let's say for example that you want to send 0x02 to the device then you would call MS5534Send(0x02, 0x08); Is this a correct assumption ? Also I'm having a hard time understanding how the statement if(bits < 0) works in the routine. If you could explain it would be much appreciated.
Thanks
login or register to reply
|
|
|
orinem
Expert Boarder |
|
2006/12/19 13:07 |
|
Re:Bit Operation Problem
ringram2077 wrote: Thanks for the code. I do have a question as to how it works. Looks like you would pass the routine a number to send to the device (bits) and a count for the number of bits to send (nbits). Let's say for example that you want to send 0x02 to the device then you would call MS5534Send(0x02, 0x08); Is this a correct assumption ? Also I'm having a hard time understanding how the statement if(bits < 0) works in the routine. If you could explain it would be much appreciated.
Thanks
Actually, to send 8 bits, you'd call MS5534Send(bitstosend<<24, 8).
The bits you want to send are shifted such that they are the highest bits in the 'bits' parameter.
The if ( bits < 0 ) statements make use of the fact that bits is declared as long and the highest bit indicates the sign of the variable, ie, if bits < 0, then the highest bit is 1. It's just another way of doing "if ( bits & 0x80000000 )".
I did it this way since the device in question requires different and odd transfer lengths, not just bytes.
In your case, you could change "long bits" to "signed char bits" and the call would be MS5534Send(bitstosend, 8).
Orin.
login or register to reply
|
|
|
ringram2077
Expert Boarder |
|
2006/12/19 14:11 |
|
Re:Bit Operation Problem
Aaaaahhhhhhhh, I see now. That is perfectly clear. The sign thing eluded me. I have been working on my routine this morning. It seems to send the transmit bits correctly but my device doesn't work. If you have a chance take a quick look and see if you might spot an error.
| Code: | //Basic SPI send and receive
unsigned char spi_comm(unsigned char outgoing_byte)
{
unsigned char incoming_byte, x;
for(x = 0 ; x < 8 ; x++)
{
//SCL = 0; //Toggle the SPI clock
GPIOPinWrite(GPIO_PORTA_BASE, SSI_CLK, 0);
if (outgoing_byte & 0x80) //is bit 7 one ?
{
GPIOPinWrite(GPIO_PORTA_BASE, SSI_TX, SSI_TX); //yes
outgoing_byte <<= 1;
}
else
{
GPIOPinWrite(GPIO_PORTA_BASE, SSI_TX, 0); //no
//SSI_TX = outgoing_byte.7; //Put bit on SPI data bus
outgoing_byte <<= 1; //Rotate byte 1 to the left
}
//SCL = 1;
GPIOPinWrite(GPIO_PORTA_BASE, SSI_CLK, SSI_CLK);
incoming_byte <<= 1; //Rotate byte 1 to the left
if(GPIOPinRead(GPIO_PORTA_BASE, SSI_RX)) //is receive line high?
{
incoming_byte |= 0x01; //yes, set bit 0 to one
}
else
{
incoming_byte &= 0xFE; //no, set bit 0 to zero
}
}
|
I plan to give your code a try next.
Thanks
Richard
Post edited by: ringram2077, at: 2006/12/19 16:33
login or register to reply
|
|
|
orinem
Expert Boarder |
|
2006/12/19 18:48 |
|
Re:Bit Operation Problem
Not enough time between setting the clock and reading the input?
GPIOPinWrite(GPIO_PORTA_BASE, SSI_CLK, SSI_CLK);
// Try some delay here
incoming_byte <<= 1; //Rotate byte 1 to the left if(GPIOPinRead(GPIO_PORTA_BASE, SSI_RX)) //is receive line high?
That's the kind of trouble I had.
I assume your device reads DIN on the rising edge of the clock. When does it change DOUT?
Make sure you got your IO pins set up correctly for input/output:
// Setup our IO pins GPIODirModeSet(GPIO_PORTA_BASE, MS5534_SCLK | MS5534_DIN, GPIO_DIR_MODE_OUT); GPIODirModeSet(GPIO_PORTA_BASE, MS5534_DOUT, GPIO_DIR_MODE_IN);
You might want to initialize the clock line here too. It's possible that the device might see a phantom clock here if the line had floated high after reset. Not a problem if the device has a chip select line and you are using it. You have to find some way of syncing up sending bit 7 with the device receiving bit 7 otherwise.
Orin.
Post edited by: orinem, at: 2006/12/19 18:51
Post edited by: orinem, at: 2006/12/19 19:07
login or register to reply
|
|