0
votes

I'm working with an LPC1788 microcontroller and I'm trying to send and receive data from a UFDC-1 (universal frequency-to-digital converter) using SPI. I'm able to transmit data across the MOSI to it fine (I've confirmed this with an oscilloscope), but whenever I send an instruction like "get accuracy", the only data I have in my data buffer is the data or instructions I just sent. "Loop back" is not enabled.

This is the code I have:

SSP_CFG_Type sspConfig;
SSP_DATA_SETUP_Type sspData;
LPC_SSP_TypeDef *SSPx = NULL;

UFDC_RESULT_T result_SSP0_FX1, result_SSP0_FX2;
UFDC_RESULT_T result_SSP1_FX1, result_SSP1_FX2;
UFDC_RESULT_T *result, *resultFX1, *resultFX2 = NULL;

uint8_t resultSign;
uint64_t resultInt, resultFract;

uint8_t SSP0resultFX1sign, SSP0resultFX2sign;
uint8_t SSP1resultFX1sign, SSP1resultFX2sign;

uint64_t SSP0resultFX1int, SSP0resultFX2int;
uint64_t SSP1resultFX1int, SSP1resultFX2int;

uint64_t SSP0resultFX1fract, SSP0resultFX2fract;
uint64_t SSP1resultFX1fract, SSP1resultFX2fract;

uint16_t getAccInstr = 0x01FF;
uint16_t setAccInstr = 0x020A;
uint16_t checkStatusInstr = 0x03FF;
uint16_t setMeasureModeInstr1 = 0x0600;
uint16_t setMeasureModeInstr2 = 0x060E;
uint16_t getBCDResultInstr = 0x07FF;
uint8_t startMeasureInstr = 0x09;

uint32_t measureInstr;

uint8_t txData[2];
uint8_t rxData[2];

uint16_t data;

sspConfig.CPHA = SSP_CPHA_FIRST;
sspConfig.CPOL = SSP_CPOL_HI;
sspConfig.ClockRate = 100000;
sspConfig.Databit = SSP_DATABIT_16;
sspConfig.Mode = SSP_MASTER_MODE;
sspConfig.FrameFormat = SSP_FRAME_SPI;

sspData.tx_data = txData;
sspData.rx_data = rxData;
sspData.length = 2;

printf("Initialising SSP0 and SSP1...\n\n");

PINSEL_ConfigPin(0, 15, 2); // SSP0_SCK
PINSEL_ConfigPin(0, 16, 2); // SSP0_SSEL
PINSEL_ConfigPin(0, 17, 2); // SSP0_MISO
PINSEL_ConfigPin(0, 18, 2); // SSP0_MOSI
PINSEL_ConfigPin(0, 6, 2); // SSP1_SCK
PINSEL_ConfigPin(0, 7, 2); // SSP1_SSEL
PINSEL_ConfigPin(0, 8, 2); // SSP1_MISO
PINSEL_ConfigPin(0, 9, 2); // SSP1_MOSI

PINSEL_SetFilter(0, 7, DISABLE);
PINSEL_SetFilter(0, 8, DISABLE);
PINSEL_SetFilter(0, 9, DISABLE);

SSP_Init(LPC_SSP0, &sspConfig);
SSP_Init(LPC_SSP1, &sspConfig);
SSP_Cmd(LPC_SSP0, ENABLE);
SSP_Cmd(LPC_SSP1, ENABLE);

printf("Reading UDFC frequency values...\n\n");
for(int i=0; i < 2; i++)
{
  if(i == 0)
  {
    SSPx = LPC_SSP0;
    resultFX1 = &result_SSP0_FX1;
    resultFX2 = &result_SSP0_FX2;
  }
  else
  {
    SSPx = LPC_SSP1;
    resultFX1 = &result_SSP1_FX1;
    resultFX2 = &result_SSP1_FX2;
  }

  // Set UFDC accuracy to 1%.
  SSP_SendData(SSPx, setAccInstr);
  while(SSPx->SR & SSP_SR_BSY);

  // Check accuracy.
  while(1)
  {
    printf("Sending data...\n");
    SSP_SendData(SSPx, getAccInstr);

    while(SSPx->SR & SSP_SR_BSY);

    // Wait to receive back data.
    while(SSPx->SR & SSP_SR_RNE)
    {
      printf("Received data here: 0x%x\n", SSP_ReceiveData(SSPx));
    }

    //data = SSP_ReceiveData(SSPx);
    //printf("Accuracy check 1: %i\n", data >> 8);
    //printf("Accuracy check 2: %i\n", data & 0xFF);
  }

Edit: Here is a capture of all my SPI lines after sending a "set accuracy" instruction (0x020A). The data across the MISO is expected to be meaningless here. I can produce captures for other instructions if necesssary.

From top to bottom:

  • MISO
  • MOSI
  • SS
  • SCLK

Edit 2: Specifically, what I'm trying to do is set the accuracy of the UFDC-1 with the instruction 0x020A. The last part of that ("0A") is the accuracy number. After that, I have a while loop where I try to read that accuracy back. The "get accuracy" instruction is 0x01FF, where "FF" is a dummy byte sent in order to read back the accuracy number. Therefore when I send "0x01FF", I expect to be reading back "0A" somewhere in the data I get sent back from the UFDC-1.

Edit 3: Here is a capture of the SPI lines as I send the "get accuracy" instruction to the UFDC-1 for the first time. The blue line (second from top) is the MOSI, and it is definitely giving the right command (0x01FF). If this were working properly, the UFDC-1 should be replying across the MISO with "0A" (0b00001010), which is the accuracy number, during the same time as the MOSI transmits "FF". Instead I get "1A" transmitted back at that time, and I don't believe that "A" is actually coming from the UFDC-1, but just from the "set accuracy" instruction (0x020A) I sent earlier. This is because I have the "get accuracy" instruction going in a while loop, and the steady-state value that I'm reading back is "0x7F00" - nothing to do at all with the accuracy number of the UFDC-1.

This is what my output looks like:

Initialising SSP0 and SSP1...

Reading UDFC frequency values...

Sending data...
Received data here: 0xff00
Received data here: 0xa1a
Sending data...
Received data here: 0xff00
Sending data...
Received data here: 0x7f00
Sending data...
Received data here: 0x7f00
Sending data...
Received data here: 0x7f00
Sending data...
Received data here: 0x7f00
Sending data...
Received data here: 0x7f00
Sending data...

Edit: Turns out the problem was with the CPOL and CPHA bits. They've both been changed from 0 to 1. That seems to let the SPI controller interact properly with the UFDC.

One problem remaining is that the SPI clocks in random data on the MISO. For instance, I have a while loop where I expect to get back nothing but "0xedff". What I get instead is:

Data : 0xedff
Data : 0xffff
Data : 0xff01
Data : 0xffff
Data : 0xedff
Data : 0xedff
Data : 0xedff
Data : 0xedff
Data : 0xedff
Data : 0xedff
Data : 0xedff
Data : 0xedff
Data : 0xedff
Data : 0xedff
Data : 0xedff
Data : 0xedff
Data : 0xedff
Data : 0xedff
Data : 0xedff
Data : 0xedff
Data : 0xedff
Data : 0xedff
Data : 0xedff
Data : 0xedff
Data : 0xedff
1
I don't quite understand your question. But I'm guessing your are expecting the received data in the buffer but not getting it. Have you looked at the SPI signal on the UFDC-1 datasheet? I do not know how the chip select line is handled by your function. Most SPI pheripheral ICs do require the master to keep the chip selected to respond to a command. - Thanushan
"But I'm guessing your are expecting the received data in the buffer but not getting it." Yep. I'll update the question with clarification. "Most SPI pheripheral ICs do require the master to keep the chip selected to respond to a command" My microcontroller seems to be handling this automatically, based on the captures I got from the oscilloscope. The slave select seems to be held down until the entire command is sent. - Tagc
Are you getting any response back from UFDC-1, looking with the scope? I think the chip select line is handled by the SSP_SendData() and SSP_ReceiveData. But the UFDC-1 might want to keep the line low until the response is send, ie not pulling it high after writing instruction and then pulling it low to receive data (only a guess). - Thanushan
Because of the way I'm doing it right now, the command to get the accuracy and the dummy byte to read it from the UFDC-1 all take place in the space of one 16-bit transfer, so the chip select is kept low throughout anyway. I took another capture to show what happens during the first "get accuracy" instruction and will update my question with it. - Tagc
I've wondered if maybe I need to send the first part of the instruction (0x01), wait a bit and then send the dummy byte (0xFF) to give the UFDC-1 time to process? I tried that and it didn't work, but I haven't tried that while keeping the slave select manually held down. Maybe that's worth a shot... - Tagc

1 Answers

0
votes

The SSPs in the LPC17xx have FIFOs for both transmit and receive. That means you must match your SSP_SendData() and SSP_ReceiveData() calls, or empty the FIFO. You will also have to send a dummy value when receiving data - usually 0x00 or 0xFF is used as dummy.

The library does this in SSP_ReadWrite() which you can use instead.

A simpler version would look like this:

uint16_t spi_write_read( LPC_SSP_TypeDef* SSPx, uint16_t outgoing )
{
    uint16_t incoming;

    while( !( SSPx->SR & (1 << SSP_SR_TNF ) ) ) { ; }
    SSPx->DR = outgoing;
    while( !( SSPSR & ( 1 << SSP_SR_RNE ) ) ) { ; }
    incoming = SSPx->DR;

    return incoming;
}

This function can be used as a replacement for both SSP_SendData() and SSP_ReceiveData() in your code.

Final note: You probably don't want hardware Chip Select, as this can de-select the slave between the command and response words. Read the corresponding datasheets, in many cases this is not allowed.