0

Am trying to read the chip_id of the BMP280 Pressure/Tempeture sensor using the Tiva TM4C123G Launchpad thought the SPI communication protocol.

To begin with let me provide some back ground info and technical details.

Inventory:

  1. Tiva TM4C123G Launchpad.Datasheet
  2. BMP280 Digital Pressure Sensor. Datasheet
  3. Female-to-Male Jumper Wire Dupont Cable x6.
  4. Breadboard
  5. IAR Embedded Workbench

To communicate with the sensor the Tiva Launchpad will behave as a Master:

GPIO Port D will be used for Serial Peripheral Interface (SPI)

  • PD3(Tx), PD2(Rx) & PD0(Clk)

GPIO Port F will work as our Sleve Slect (Chip Select) signal

  • PF2(SS- Slave Select)

Pin Configuration:

TM4C123G BMP280
+3.3V VCC
GND GND
PD0 SCL
PD3 SDA
PF2 CSB
PD2 SD0

CODE

/*-------------LIBRARIES-------------*/
#include <TM4C123GH6PM.h>               
#include "stdio.h"

/*---------FUNCTION PROTOTYPES---------*/
void init_SSI1(void);                   //SSI Module 1 Initialization Function
void delay_ms(uint32_t period_ms);      //Time Delay Function 

void cs_low(uint8_t dev_id);
void cs_high(uint8_t dev_id);

int8_t spi_reg_read(uint8_t cs, uint8_t reg_addr);

int main()
{
  int8_t rslt;
  init_SSI1();                          /* Tiva SSI Module 1 Initialization and Configuration call*/
  rslt = spi_reg_read(0x00, 0xD0);      // Reads the chip-id data from the sensor
        
  return 0;
}

void init_SSI1(void)
{
  SYSCTL->RCGCSSI |= 2;                 /* Enable clock to SSI1 */
  SYSCTL->RCGCGPIO |= 8;                /* Enable clock to GPIOD for PD3(Tx), PD2(Rx) & PD0(Clk) */
  SYSCTL->RCGCGPIO |= 0x20;             /* Enable clock to GPIOF for PF3 (- SSslave select) */
  
  /* Configure PD3(Tx), PD2(Rx) & PD0(Clk) as ALT function for SSI1 */
  GPIOD->AMSEL &= ~0x0D;                /* Disable analog for this pins */
  GPIOD->AFSEL |= 0x0D;                 /* Enable Alternative Function */
  GPIOD->PCTL &= ~0x0000FF0F;           /* assign pins to SSI1 */
  GPIOD->PCTL |= 0x00002202;            /* assign pins to SSI1 */
  GPIOD->DEN |= 0x0D;                   /* And make them digital */  
  
  /* Configure PORTF 2 for slave select */
  GPIOF->DIR |= 0x04;                    // Make the pin output
  GPIOF->DEN |= 0x04;                    // Make the pin digital 
  GPIOF->DATA |= 0x04;                   // Keep SS idle high 
  
  /* SPI Master, POL = 0, PHA = 0, Clock = 8 MHz, 16 bit data */
  SSI1->CR1 = 0;                        /* disable SSI and make it master */
  SSI1->CC = 0;                         /* use system clock */ 
  SSI1->CPSR = 2;                       /* prescaler divided by 2 */
  SSI1->CR0 = 0x0007;                   /* 8 MHz SSI clock, SPI mode, 8 bit data */
  SSI1->CR1 |= 2;                       /* enable SSI1 */ 
}

void delay_ms(uint32_t period_ms)
{
  /* Implement the delay routine according to the target machine */
  /* milliseconds delay using one-shot mode*/
  SYSCTL->RCGCTIMER |= 1;               //enable clock to Timer Block0
  TIMER0->CTL = 0;                      //disable Timer before initialization
  TIMER0->CFG = 0X04;                   //16-bit option
  TIMER0->TAMR = 0X01;                  //one-shot mode and down-counter
  TIMER0->TAILR = 16000 * period_ms - 1;//Timer A interval load value register
  TIMER0->ICR = 0X1;                    //clear the TimerA timeout flag. 
  TIMER0->CTL = 0X01;                   //enable Timer A after initialization
  while ((TIMER0->RIS & 0x1) == 0) {    //wait for TimerA timeout flag to set
  }
}

void cs_low(uint8_t dev_id)
{
    if (dev_id == 0)
    {
        GPIOF->DATA &= ~0x04;                 /* Assert SS low */
    }
    else if (dev_id == 1)
    {
        GPIOF->DATA |= 0x04;                  /* keep SS idle high */ 
    }
}

void cs_high(uint8_t dev_id)
{
    if (dev_id == 0)
    {
        GPIOF->DATA |= 0x04;                  /* keep SS idle high */
    }
    else if (dev_id == 1)
    {
        GPIOF->DATA &= ~0x04;                 /* Assert SS low */
    }
}

int8_t spi_reg_read(uint8_t cs, uint8_t reg_addr)
{
  int8_t rslt;                          
  uint8_t data;

  /*
   * The parameter dev_id can be used as a variable to select which Chip Select pin has
   * to be set low to activate the relevant device on the SPI bus
   */

  /*
   * Data on the bus should be like
   * |----------------+---------------------+-------------|
   * | MOSI           | MISO                | Chip Select |
   * |----------------+---------------------|-------------|
   * | (don't care)   | (don't care)        | HIGH        |
   * | (reg_addr)     | (don't care)        | LOW         |
   * | (don't care)   | (reg_data[0])       | LOW         |
   * | (....)         | (....)              | LOW         |
   * | (don't care)   | (reg_data[len - 1]) | LOW         |
   * | (don't care)   | (don't care)        | HIGH        |
   * |----------------+---------------------|-------------|
   */
  
  cs_low(cs);
  while ((SSI1->SR & 0x02) == 0);       /* wait until FIFO not full */
  SSI1->DR = 0xD0;                      /* Read Command */
  while ((SSI1->SR & 0x02) == 0);       /* wait until FIFO not full */
  while ((SSI1->SR & 0x04) == 0);       /* wait until FIFO not Empty */
  data = SSI1->DR;                      /* read the received byte */
  while(SSI1->SR & 0x10);               /* wait until SSI is idle (transmit complete) */  
  cs_high(cs);
  
  return rslt;
}

Additional Resources

Tiva TM4C123G Launchpad Datasheet

BMP280 Digital Pressure Sensor Datasheet

BMP280 sensor API - Github


The BPM280 datasheet has the following instructions for reading (p. 31):

enter image description here

The chip_id reg addr is 0xD0 (Take a look to p.24). I will understand that control byte will remain the same: 0xD0. I'm unable to obtain 0x58 from the sensor, as specify by the BMP280 datasheet. I will appreciate if anyone can provide me any help. In specific an eye on the spi_reg_read function.

  • 2
    What happens on your scope/logic analyser when you send the control byte? Check all 4 SPI lines. If you are using a scope with limited amount of channels, then a tip is to connect slave select as external trigger (falling edge trig). – Lundin Jan 15 '21 at 11:43
  • 1
    Also, might be a good idea to assign `rslt` to the result stored in `data`... hello compiler warnings. – Lundin Jan 15 '21 at 11:48
  • @Lundin I don't have at the moment a scope/logic analyzer. I guess this will be a good opportunity to buy one. I did make a quick search and notice some of them are expensive. Any specific logic analyzer that you can recommend? - I also found some USB logic analyzer. Any feedback about it much appreciated. – Alex Roman Jan 17 '21 at 15:04
  • If your budget is tight I'd recommend a 2 channel oscilloscope. It's much more multi-purpose than a logic analyser. Some scopes also have inputs for logic analyser probes but those tend to cost extra. Maybe buy a used one from one of those companies that rent & repair old instruments. The old school cathode rays ones for example might not look so pretty nowadays, but they were always high quality. – Lundin Jan 18 '21 at 07:11

0 Answers0