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.

HIH 9131 SPI issue

Other Parts Discussed in Thread: TM4C123GH6PM

Hi guys! A few month ago I created a post before starting to use Honeywell's HIH9131 sensor (https://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/510084 ). I started playing with this guy this week and I can't really make it work, and I need it in order to measure relative humidity and temperature. First of all here's the schematic:

The top part is in one board and the bottom one is another board. I'm using TM4C123GH6PM with TIvaWare, and Coocox with GCC to program. I'm also attaching sensor's datasheet and SPI comms app note to understand how it works.

So, how I understood it works:

- 8 bit read to wake it up (I send a dummy byte) and provide clock

- Read and discard data

- Wait 36.56mS for conversion

- Read 4 bytes providing clock (I send 4 dummy bytes)

Here's my code:

int main(void)
{
int txdata=0xAA;
int HR_LSB = 0;
int HR_MSB = 0;
uint32_t pui32DataRx[2];
//
// Initialization
Initialize();

// PF0 Rx
// PF1 Tx Not used
// PF2 Clk
// PF3 Fss/CS
//
// Enable SSI1
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1);
SysCtlDelay(10);
// Disabling SSI to configure
SSIDisable(SSI1_BASE);
// Set clock source
SSIClockSourceSet(SSI1_BASE, SSI_CLOCK_SYSTEM);
// GPIO config
GPIOPinConfigure(GPIO_PF2_SSI1CLK);
GPIOPinConfigure(GPIO_PF3_SSI1FSS);
GPIOPinConfigure(GPIO_PF0_SSI1RX);
GPIOPinConfigure(GPIO_PF1_SSI1TX);
GPIOPinTypeSSI(GPIO_PORTF_BASE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
// Max clock input is 800kHz
//SSIConfigSetExpClk(SSI1_BASE, (SysCtlClockGet()), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 10000, 8);
SSIConfigSetExpClk(SSI1_BASE, 400000, SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 1000, 16);
// Enable SSI1
SSIEnable(SSI1_BASE);

//

while(1)
{

// TODO: Measurement Request command
SSIDataPutNonBlocking(SSI1_BASE, 0xAA);
SSIDataGet(SSI1_BASE, &txdata);
// TODO: Conversion time: 36.65mS
delayMS(40);
//
// Re-configure for 16 bit
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1);
SysCtlDelay(10);
SSIDisable(SSI1_BASE);
SSIClockSourceSet(SSI1_BASE, SSI_CLOCK_SYSTEM);
GPIOPinConfigure(GPIO_PF2_SSI1CLK);
GPIOPinConfigure(GPIO_PF3_SSI1FSS);
GPIOPinConfigure(GPIO_PF0_SSI1RX);
GPIOPinConfigure(GPIO_PF1_SSI1TX);
GPIOPinTypeSSI(GPIO_PORTF_BASE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
SSIConfigSetExpClk(SSI1_BASE, 400000, SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 1000, 32);
SSIEnable(SSI1_BASE);
// TODO: Data Fetch
SSIDataPutNonBlocking(SSI1_BASE, 0xAAAA);
SSIDataGetNonBlocking(SSI1_BASE, HR_MSB);
SSIDataPutNonBlocking(SSI1_BASE, 0xAAAA);
SSIDataGetNonBlocking(SSI1_BASE, HR_LSB);
delayUS(640);
}

}

I probed clock going to the sensor and I'm getting 100kHz (datasheet says clock's frequency should be between 50 and 800kHz), 8 clock cycles to convert, I wait 40mS and then 16 clock cycles.

I probed Chip Select and I get one in the middle of the reading sequence (I think it is because I am sending two bytes at a time instead of four bytes in a roll):

And when I probe Rx I can see something like the next pic. Data is changing, that's good, but it seems to be repeating two times (Again I think that's because I'm sending two bytes at a time).

The thing is I don't get any read data to HR_MSB or HR_LSB, they are always zero. I already tried everything that came to my head, but I always get the same result. I followed Rx path and it's going from the sensor to microcontrolle's pin, so I didn't see any issue here.

I would appreciate every comment or fresh idea to try and thanks in advance!

Franco.

001 HIH9000 Datasheet.pdf

0160.005 SPI Comms with Digital Humidity_Temp Sensors TN_009071-1-EN_Final_07Jun12.pdf

  • I suspect your conclusions about the problem source are correct for the chip select. I would advise not using the builtin chip select functionality, I've so far only seen one manufacturer's implementation approach being correct and TI is not that manufacturer. Instead toggle the chip select line yourself.

    As far as not receiving input, maybe you have run afoul of TI putting an NMI on the pinout. In order to partially compensate for that they've made it necessary to jump through hoops to change the functionality of some pins. Check the data sheet to see if you are using some of the affected pins. There have been multiple posts here about the incantation needed to change the function of the affected pins.

    Robert
  • Thanks Robert, actually I was about to check "Diagnosing Common Development Problems and Tips & Info for TM4C Devices" and PF0 is a locked pin, so I'll try to unlock it and come back to update.

    About CS pin, I was using it as a GPIO, but I was innocent enough to think that library could take care of it. I think I'll go back to the way it was before.

  • Well, I could fix CS issue and now I can see the first two bytes changing according to relative humidity and the last two bytes changing according to temperature. Manually manipulating CS pin was the answer.

    I tried to unlock PF0 but I wasn't able to. I tried with this piece of code:

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
    HWREG(GPIO_PORTF_BASE + GPIO_O_CR) |= 0x01;
    HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = 0;

    But I'm still not able to receive anythingI've seen some posts using some other functions, but I don't really know what value I should (if I even have to) set to AMSEl and DEN registers.

    HWREG(GPIO_PORTF_BASE + GPIO_O_AFSEL) |= 0x400;
    HWREG(GPIO_PORTF_BASE + GPIO_O_DEN) |= 0x01;

    Any ideas?
  • I'm away from my similar code but I seem to recall that after unlocking the normal pin setup functions work.

    Robert
  • Hello fjpolo

    Make sure that after enabling the peripheral you check that the peripheral is ready for access. Also once the commit control bit is set then other GPIO configuration function can be used

    Regards
    Amit
  • Hi Amit, thanks for the reply. I'm not sure I follow you, how do I check that the peripheral is ready to be accessed? I've never done it before. And I don't know what you mean when you say that other GPIO configuration function can be used. Do I still need to add a piece of code? Sorry again, I'm a bit lost here.

    Franco

  • Hello Franco,

    When the GPIO CR bit has been set, the any GPIO function like GPIOPinTypeGPIOOutput or GPIOPinConfigure etc can be used. Setting AMSEL, DEN or any other GPIO register is automatically handled by these API.

    Regards
    Amit
  • Hi guys, thanks to everyone for your support. Code is working now, to summarize:

    - Using CS as GPIO
    - Unlocked PF0
    - Variable for SSIDataGet must match frame size on SSIConfigSetExpClk

    My code in case anyone needs help:



    int main(void)
    {
    uint32_t pui32DataRx[2];
    double t_bs;
    double hr;

    //
    // Initialization
    Initialize();
    // PF0 Rx
    // PF1 Tx Not used
    // PF2 Clk
    // PF3 Fss/CS
    //
    // Enable SSI1
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    SysCtlDelay(10);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1);
    SysCtlDelay(10);
    // Unlock PF0
    HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
    HWREG(GPIO_PORTF_BASE + GPIO_O_CR) |= GPIO_PIN_0;
    HWREG(GPIO_PORTF_BASE + GPIO_O_AFSEL) |= GPIO_PIN_0;
    HWREG(GPIO_PORTF_BASE + GPIO_O_DEN) |= GPIO_PIN_0;
    HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = 0;
    //SSIDisable(SSI1_BASE);
    SysCtlDelay(10);
    // Set clock source
    SSIClockSourceSet(SSI1_BASE, SSI_CLOCK_SYSTEM);
    // GPIO config
    GPIOPinConfigure(GPIO_PF2_SSI1CLK);
    //GPIOPinConfigure(GPIO_PF3_SSI1FSS);
    GPIOPinConfigure(GPIO_PF0_SSI1RX);
    GPIOPinConfigure(GPIO_PF1_SSI1TX);
    GPIOPinTypeSSI(GPIO_PORTF_BASE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2);
    SSIConfigSetExpClk(SSI1_BASE, 400000, SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 1000, 16);
    // CS/FSS as GPIO
    GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_3);
    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_PIN_3);
    // Enable SSI1
    SSIEnable(SSI1_BASE);
    //
    //
    //
    while(1)
    {
    // TODO: Measurement Request command
    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0);
    SSIDataPutNonBlocking(SSI1_BASE, 0xAA);
    SSIDataGet(SSI1_BASE, &txdata);
    delayUS(160);
    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_PIN_3);
    // TODO: Conversion time: 36.65mS
    delayMS(40);
    // TODO: Data Fetch
    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0);
    SSIDataPutNonBlocking(SSI1_BASE, 0x0000);
    SSIDataGet(SSI1_BASE, &pui32DataRx[0]);
    SSIDataPutNonBlocking(SSI1_BASE, 0x0000);
    SSIDataGet(SSI1_BASE, &pui32DataRx[1]);
    delayUS(330);
    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_PIN_3);
    // hr
    hr = pui32DataRx[0] & 0x3FFF;
    hr = hr*100;
    hr = hr/16382;
    // tbs
    t_bs = pui32DataRx[1] & 0x3FFF;
    t_bs = t_bs*165;
    t_bs = t_bs/16382;
    t_bs = t_bs-40;
    //
    delayUS(310);
    }
    }