Project 6.1 Using the SPI and I2C bus

Configuring and using common serial busses

797

Introduction

For this project, you will configure the SPI and I2C busses on ZYNQ to communicate with peripheral devices.

Background

Most peripheral devices used in digital systems today use serial busses to communicate with the processor. Several serial busses are commonly used, including UART, SPI, I2C, CAN, and others. In the previous project you used the UART bus to move data between the Blackboard and the PC. In this project, you will communicate with on-board sensors using the two most popular serial busses - SPI and I2C.

The Blackboard includes an ST Microelectronics inertial module that contains an accelerometer, a gyroscope, and a magnetometer. Inertial modules like this are commonly used in mobile platforms like drones or robots to sense relative motion and position. In the first part of this project, you will write a C program to access these sensors using the SPI bus, and display the sensor data on the PC using the UART and terminal program.

After you can communicate with the sensors, you will setup interrupts to manage the SPI bus so you don’t need to spend time in polling loop.

The Blackboard also contains a temperature sensor that is connected to the ZYNQ device using an I2C bus. In the second part of this project, you will access the temperature sensor and display its output on the PC. Then, as with the SPI bus, you will configure interrupts to manage the I2C bus.

Requirements

1. Read data from Blackboard’s inertial module, and send the data to the PC using the UART

Write a C function that can read data from any one of the inertial module registers (your function should get the register address as an argument). Then use the function to read the WHO_AM_I registers from the ACC/Gyro and the magnetometer, and send the register contents to the PC using your UART code from the previous project. Use the terminal program to display the register values in decimal, and verify they are correct. The WHO_AM_I registers are located at address 0x0F. The ACC/Gyro register can be read by asserting Slave Select 0 (SS0), and the magnetometer can be read by asserting SS1. Your function should look something like the following.

void SPI_read(uint32_t CS, uint32_t address) { }

2. Configure and read the inertial sensor, and send the data to the PC

Create a C function that can write data to any one of the inertial module registers (so, your function should input the register address and data as arguments). Then use your function to configure the ACC/Gyro by writing 0x20 to the CTRL_REG1_G register at address 0x10 (refer to iNEMO section within the BBPR manual or to the LSM9DS1 data sheet for more information). Then use the read function to read data from the gyroscope, accelerometer, and magnetometer (one at a time) and display the data on your computer using the UART and terminal program. Your function should look something like the following.

void SPI_write(uint32_t CS, uint32_t address, uint32_t write_data) { }

3. Use interrupts to interact with the inertial module

Setup the global timer to create an interrupt once per second, read one of the instruments in the inertial module at each interrupt, and send the data to the PC using the UART. Also setup and use SPI interrupts (ID #58) so that you don’t need to poll to see when new data is available.

Your program should setup the interrupts, configure the needed peripheral devices, and then execute a “while 1” loop. At each timer interrupt, launch an SPI read to retrieve data from one of the instruments, and return to the while 1 loop. When the SPI interrupt informs you that new data is available, read the data and transfer it to the UART.

4. Read and display temperature data

Poll one of the pushbuttons, and read a temperature value from the LM75 temperature sensor (I2C) each time the button is pressed. Send the temperature value to the UART for display in the terminal program.

5. Use interrupts to interact with the temperature module

Setup the global timer to create an interrupt once per second. At each interrupt, read the temperature, and send the data to the PC using the UART. Also setup and use I2C interrupts (ID #80) so that you don’t need to poll to see when new data has been written, or when new data is available.

Your program should setup the interrupts, configure the needed peripheral devices, and then execute a “while 1” loop. At each timer interrupt, launch an I2C read to retrieve temperature data, and then return to the while 1 loop. When the I2C interrupt informs you that new data is available, read the data and transfer it to the UART.

Challenge

1. Create a system that can read any of the sensors.

Create a program to use two MIO buttons (BTN4 and BTN5) to start and stop reading data from the inertial module and temperature sensor. Your program should use interrupts wherever possible (i.e. responding to button presses and managing bus transactions).

Use two slide switches to setup operating modes:

  • SW[1:0] = 00 Display accelerometer X, Y, and Z values
  • SW[1:0] = 01 Display gyroscope X, Y, and Z values
  • SW[1:0] = 10 Display magnetometer X,Y, and Z values
  • SW[1:0] = 11 Display XADC voltage value

When button 4 is pressed, read the slide switches and send the selected data values to the PC once per second. When button 5 is pressed, stop sending values.