0

I am new to the whole embedded hardware thing, and I am getting stuck when trying to connect my STM32F4 Discovery board to a Bosch BMX_055 IMU unit.

Here is a snippet of the code I am trying to run:

bool testConnection() {
    SPI_ResetCS(&IMUSpi);
    SPI_Transfer8(&IMUSpi, 0x0);
    int chipId = SPI_Transfer8(&IMUSpi, 0x0);
    printf("Chip Id: %d\n", chipId);
    SPI_SetCS(&IMUSpi);
    return true;
}

My code then gets hung up in here:

inline uint8_t SPI_Transfer8(Spi* spi, uint8_t value) {
    *(uint8_t *)(&spi->spiPeriph->DR) = value;
    SPI_WaitTX(spi->spiPeriph);
    SPI_WaitRX(spi->spiPeriph);
    //SPI_WaitBSY(spi->spiPeriph);
    return *(uint8_t *)(&spi->spiPeriph->DR);
}

on the SPI_WaitTX function.

Any ideas on why it is stuck/how to fix it would be greatly appreciated!

SamGibson
  • 17,231
  • 5
  • 37
  • 58
  • From datasheet, BMX055 has PS (Protocol Select) pin #7, value of LOW selects SPI mode (otherwise I2C). – Flanker Aug 11 '16 at 05:07

2 Answers2

3

There is lots of code that you haven't given to us, but since you are new to the STM32 family, I will explain the "classic cause" for this type of problem as this is probably the cause for you too.

  • On many STM32 cores, including the STM32F4 on your board, the various peripheral block clocks are disabled by default, to save power. If your code tries to access an unclocked peripheral block, you trigger a "Bus Fault" in the core.

  • A "hang" on devices with ARM Cortex-M3 & M4 cores, is commonly caused by code which has either:

    a) triggered a "Fault" type which is not a "Hard Fault", but does not have a registered fault-handler for that specific type of Fault; this then causes it to be escalated to become a "Hard Fault"; or

    b) directly triggered a "Hard Fault".

    The default "Hard Fault handler" for many Cortex-M3 & M4 toolchains is a simple infinite loop e.g. while (1) {}. You can install your own Fault handler code, but unless you do that, then triggering any type of Fault typically becomes a hang in a Fault handler. For simple investigations, you can then use your SWD/JTAG‑attached debugger to find more about the core's state and read the relevant registers to find more information.

Now you can see that you put those two situations together and a hang which occurs on the first access to a peripheral block (in your case, SPI), is likely to be because you didn't enable the clock to that peripheral block. That attempted access triggers a Bus Fault. Either the default Bus Fault handler in your toolchain is an infinite loop, it was enabled (e.g. in your toolchain's startup code) and your core is sitting in that loop, or no Bus Fault handler was enabled so this Fault was escalated to become a Hard Fault, and you are sitting in the Hard Fault handler's infinite loop.

If my hypothesis is correct for your case, at least part of the fix would be to enable the SPI peripheral clock module before attempting to access it, using something like this line, if you have included the CMSIS headers:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

I don't promise that this line is exactly correct for your MCU (it's currently too late for me to check datasheets here) but it gives you a clue of the type of thing you need to investigate. Note: You will also need to enable the peripheral clocks for whichever GPIO modules you are using for the various SPI-related pins.

P.S. In future, please try to include an MCVE (Minimum Complete Verified Example) of your code i.e. the smallest complete code example which still shows whatever problem you are requesting help with. That way, we don't have to guess what the missing code might include (or not include). Thanks!

SamGibson
  • 17,231
  • 5
  • 37
  • 58
  • Hi, thank you so much for your answer. I do not have that line of code, but I will add it and get back to you. Also, thank you for the reference to the MCVE, I will keep that in mind next time I ask a question! – Yousef Hindy Aug 11 '16 at 04:49
  • @YousefHindy - Hi - As I mentioned, you need to check whether my example line of code to enable the SPI clock, is correct for your *specific* MCU and whichever SPI module (e.g. SPI1, SPI2 etc) you are using. Different SPI modules require different commands to enable the clock. I expect you already have *some* "peripheral clock enable" code in your project (e.g. for GPIO modules), so you can use those to understand what macros and #defines your specific toolchain and headers provide. So please do some research before just copying the example I gave. If you need more help, pls give more info! – SamGibson Aug 11 '16 at 05:07
0

AFAICT, your code doesn't get far enough to demonstrate it is getting anything back from the BMX_055. So there is no proof that the circuit is correct, so consider that it may be broken.

There are several different SPI modes (combination of clock and data MOSI state), and further combinations of enable signals. It can be hard to see what, if anything, is working if you try to use the SPI peripheral. If you have access to an oscilloscope, then you can check that data is being returned from the Bosch BMX_055 IMU without actually having all your code correct (by observing the MISO pin). If you haven't access to an oscilloscope or logic analyser (and know how to use it), then I think your best tactic is to ignore the SPI peripheral hardware at first and use 'bit-banging'.

When a 'proper' SPI hardware peripheral doesn't work first time, or very easily, then drive the signals using GPIO pins and software (the technique called 'Bit Banging' and will turn up in a web serach).

So drive the clock, MOSI and Enable (it's possibly necessary) with the equivalent of digitalWrite, and get the MISO signal with the equivalent of digitalRead. Try to keep it as simple as possible.

You'll find several examples on the web if you search for 'SPI Bit-Banging'.

I found Coding SPI software
Software SPI for PIC
and a stack exchange question What is bit banging?

Here's a copy of the pseudo code from the Electronics stackexchange answer:

Make Slave Select low  
Short delay
Do 8 times
  Make the SCK (Serial Clock) pin low 
  Make the MOSI (Master-Out-Slave-In) pin high or low depending on bit 7 of the data  
  Add brief delay  
  Make the SCK output high
  Read MISO (Master-In-Slave-Out) pin
  Shift received data left, and shift the bit just read in as bit 0   
  Add brief delay  
  Shift the data byte 1 bit left
Make Slave Select high again  

You will need to read and understand the Bosch BMX_055 IMU datasheet to ensure you are talking to it correctly because there are several different SPI 'modes'. The modes are dependant on the slave device, and are the relationship between the clock state and the data.

Once you have got both electronics and signals working, then try getting the SPI peripheral working.

gbulmer
  • 10,040
  • 20
  • 29