This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Hi there,
Recently I got a project working with the MSP430F2013, using SPI over USI to read from an SD card. I am now trying to port this project to an MSP430F249, to take advantage of more I/O, and with some minor declaration tweaks, everything seems to be working except for the two primary SPI functions. The functions spiSendByte(constant unsigned char data) and MMC_initSPI(void) are set up to use SPI through USI, and I haven't been able to find any guides as to how to rewrite these using USCI. This seems to be necessary because most of the registers referenced in USI don't have direct equivalents in USCI. Can anyone help me figure out how to write these utilizing USCI, or point me in the direction of an appropriate example? I know this chip has 4 USCI, and all of them are available to me for this, everything else is much easier to move around. Thank you in advance!
The code of the two functions follows:
unsigned char spiSendByte(const unsigned char data)
{
while (!(USICTL1&USIIFG)); // Wait for RX to finish
USISRL=data;
USICNT = 8; // send 8 bits of data
while (!(USICTL1&USIIFG)); // Wait for RX to finish
return (USISRL); // Store data
}
void MMC_initSPI(void){
//chip select
SD_CSn_PxDIR|=SD_CSn_PIN;
SD_CSn_PxOUT|=SD_CSn_PIN;
USICTL0 |= USIPE7 + USIPE6 + USIPE5 + USIMST + USIOE; // Port, SPI master
//USICTL1 |= USICKPH; // USICKPH; // Counter interrupt, flag remains set
USICKCTL = USIDIV_0 + USISSEL_2 + USICKPL; // /4 SMCLK + USICKPL +
USICTL0 &= ~USISWRST; // USI released for operation
}
Teh 249 has two USCIs, which differ slightly. USCI0 uses different registers for interrupt control than USCI1.
I will refer to the USCI0.
usnigned char spiSendByte(const unsigned chat data)
{
while (!(IFG2&UCA0TXIFG));
UCA0TXBUF = data;
while (!(IFG2&UCA0RXIFG));
return UCA0RXBUF;
}
However, this function that sends a byte and returns the result, is a bit inefficient. On the USI, this was the only way, btu the USCI allows for double buffering. So you can start sending/receiving the next byte before you return with the previous byte. It allows for much higher throughput up to a seamless operation.
void MMC_InitSPI(void){
// setup the pins here - depends on MSP as well as on the PCB layout.
// The USCI does not need the direction setting for the SOMI., SIMO and SCLK pins, but I don't know whether SD_CSn_PIN contains more than that
// Also, the USCI has its pins enabled by the PxSEL register rather than the USIPEx bits.
UCA0CTL0 = UCMST|UCMODE_0|UCSYNC; // add UCCKPH, UCCKPL, UCMSB if needed
UCA0CTL1 = UCSWRST|UCSSEL_2; // USCICLK = SMCLK
UCA0BR0 = 4; // SPICLK = USCICLK/4
UCA0CTL1 &= ~UCSWRST;
}
For a busy-waiting SPI transfer that doesn't go for maxiumum throughput, that's it.
Thank you very much! I will try that and report back. When you say to "setup pins" in the MMC_InitSPI(), that is just a matter of assigning the correct function to the SOMI, SIMO, and SCLK pins, right?
So, for example,
P3SEL.0 = 1; // UCA0CLK function on pin 3.0
P3SEL.4 = 1; // UCA0SIMO function on pin 3.4
P3SEL.5 = 1; //UCA0SOMI function on pin 3.5
(These are from the MSP430F249 data sheet).
The SD_CSn lines just set the output direction of pin 1.4 (Used as the chip select) and assert it.
So then I should be able to connect pin 3.0 to CLK on my SD card, 3.4 to SIMO, 3.5 t SOMI, and 1.4 to CS, and then it should function? I just want to make sure I am understanding this correctly, and I will try it as soon as I get home.
For the record, the original project that I am trying to port is here: www.diylife.com/2008/04/11/make-a-singing-msp430-microcontroller-part-3/
and I think that once I have these functions working, it's just a matter of setting the correct direction and pin function for timer_A output 1 (which is 1.6 on my F249 rather than 2.6 on the F2013).
Thank you again!
EDIT: There was a problem with my port select statements when I posted the comment below. Now these signals work, but I am having problem elsewhere in the ported code with the buffers and the watchdog timer interrupts, which leads to only getting static out of the speaker. I will look into these further. Thank you again.
---Below is pre-edited comment---
Hrmm, I tried all of that, and I seem to have gotten stuck again. It seems as if data isn't being received correctly? My code runs the following MMC_ReadCardSize() routine after the MMC_InitSPI(), but it is getting stuck forever in the response loop, shown in red below. It assigns to variable 'b' the return value of spiSendByte(const unsigned char data), which is the data in UCA0RXBUF. However, it never passes the while (b !=0xFE) test, and if I pause the program and try to view registers, UCA0RXBUF is never anything other than 0x00. Any suggestions?
unsigned long MMC_ReadCardSize(void)
{
// Read contents of Card Specific Data (CSD)
unsigned long MMC_CardSize;
unsigned short i, // index
j, // index
b, // temporary variable
response, // MMC response to command
mmc_C_SIZE;
unsigned char mmc_READ_BL_LEN, // Read block length
mmc_C_SIZE_MULT;
CS_LOW ();
spiSendByte(MMC_READ_CSD); // CMD 9
for(i=4; i>0; i--) // Send four dummy bytes
spiSendByte(0);
spiSendByte(0xFF); // Send CRC byte
response = mmcGetResponse();
// data transmission always starts with 0xFE
b = spiSendByte(0xFF);
if( !response )
{
while (b != 0xFE) b = spiSendByte(0xFF); //Stuck here forever!
// bits 127:87
for(j=5; j>0; j--) // Host must keep the clock running for at
b = spiSendByte(0xff);
// 4 bits of READ_BL_LEN
// bits 84:80
b =spiSendByte(0xff); // lower 4 bits of CCC and
mmc_READ_BL_LEN = b & 0x0F;
b = spiSendByte(0xff);
// bits 73:62 C_Size
// xxCC CCCC CCCC CC
mmc_C_SIZE = (b & 0x03) << 10;
b = spiSendByte(0xff);
mmc_C_SIZE += b << 2;
b = spiSendByte(0xff);
mmc_C_SIZE += b >> 6;
// bits 55:53
b = spiSendByte(0xff);
// bits 49:47
mmc_C_SIZE_MULT = (b & 0x03) << 1;
b = spiSendByte(0xff);
mmc_C_SIZE_MULT += b >> 7;
// bits 41:37
b = spiSendByte(0xff);
b = spiSendByte(0xff);
b = spiSendByte(0xff);
b = spiSendByte(0xff);
b = spiSendByte(0xff);
}
Yep.David Zucker said:When you say to "setup pins" in the MMC_InitSPI(), that is just a matter of assigning the correct function to the SOMI, SIMO, and SCLK pins, right?
Not knowing what the constants are defined to, or what an opaque INIT function does, I cannot check those things against a datasheet.
The USCI controls the direction by itself, so no need to program the PxDIR registers.
Oen thing to keep in mind: after power-up, an SD card can only be accessed with 400kHz maximum frequency. After proper initialization, you can rise SPI clock speed to whatever the card allows (or the MSP).
**Attention** This is a public forum