Dear Team,
I'm running into difficulties writing an SPI-Driver for an Analog Devices ADE7913 ADC. Reading the value from the SSI-resource yields strange behavior that I can't explain, yet the scope shows the expected value being written on the MISO line. I'll first go through the SW-steps, describe the problem including some screenshots, and will then provide a minimal working example. Any help is very appreciated!
Here's what the code does:
1. Issue a write command to the ADC, specifying the register we want to write to: 0x70
2. Send the value we want written into the register: 0xFF (I have tried other values, as well. The behavior is identical.)
3. Issue a read command to the ADC, specifying the register we want to read from (the same as was written before): 0x74
4. Execute a dummy write in order for the CS and SPI-clock-signals to be on the line: 0x00
5. Execute a read-command on the Tiva and write the data inside the FIFO into a variable
6. Print the variable and the status of the read command to the console
7. Restart loop at 1
As you can see on the scope-screenshot, the ADC sends the correct value in response to the read-command - The MISO-line is clearly receiving 0xFF:
However, the Tiva only reads the value correctly during the pass 4 and pass 8 of the loop (255 == 0xFF), and subsequently doesn't anymore:
Here's the code:
#include <iostream>
extern "C"
{
#include <stdint.h>
#include <stdio.h>
#include "inc/hw_memmap.h"
#include "inc/hw_ssi.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/ssi.h"
}
//*****************************************************************************
//
// System clock rate in Hz.
//
//*****************************************************************************
uint32_t g_ui32SysClock;
//*****************************************************************************
//
// The error routine that is called if the driver library encounters an error.
//
//*****************************************************************************
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif
// global constants
constexpr uint32_t ssiBitsPerSecond = 250'000;
constexpr uint32_t ssiDataWidthInBits = 8; // must be between 4 and 16
// global variables
int SSIreadStatus = -1;
uint32_t data = 0xffffffff;
// functions
void spiInit(void)
{
// Enable SSI-Peripherals
SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1);
// Enable GPIO-Ports
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
// Configure GPIO Pin Mux for SSI1
GPIOPinConfigure(GPIO_PB5_SSI1CLK);
GPIOPinConfigure(GPIO_PB4_SSI1FSS);
GPIOPinConfigure(GPIO_PE4_SSI1XDAT0);
GPIOPinConfigure(GPIO_PE5_SSI1XDAT1);
// Configure the GPIO settings for the SSI pins. This function also relays
// control of these pins to the SSI hardware.
GPIOPinTypeSSI(GPIO_PORTB_BASE, GPIO_PIN_4 | GPIO_PIN_5);
GPIOPinTypeSSI(GPIO_PORTE_BASE, GPIO_PIN_4 | GPIO_PIN_5);
// Configure and enable SSI1 port for SPI master mode
SSIConfigSetExpClk(SSI1_BASE, g_ui32SysClock, SSI_FRF_MOTO_MODE_3,
SSI_MODE_MASTER, ssiBitsPerSecond, ssiDataWidthInBits);
// Enable modules SSI0, SSI1, SSI3.
SSIEnable(SSI1_BASE);
}
int main(void)
{
// Run from the PLL at 120 MHz.
// Note: SYSCTL_CFG_VCO_240 is a new setting provided in TivaWare 2.2.x and
// later to better reflect the actual VCO speed due to SYSCTL#22.
g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
SYSCTL_OSC_MAIN |
SYSCTL_USE_PLL |
SYSCTL_CFG_VCO_240), 120000000);
printf("g_ui32SysClock = %d\n\n", g_ui32SysClock);
spiInit();
int count = 0;
while(1)
{
// SPI-Test: Write to EMI_CTRL register of ADE7912. Then read written value from ADE7912.
{
SSIDataPut(SSI1_BASE, ((0xE << 3) | 0b000));
SSIDataPut(SSI1_BASE, 0xFF);
while(SSIBusy(SSI1_BASE))
{
}
SSIDataPut(SSI1_BASE, ((0xE << 3) | 0b100));
// HWREG(SSI1_BASE + SSI_O_DR) = ((0xE << 3) | 0b100); // write-command on register level (vs. TivaWare)
SSIDataPut(SSI1_BASE, 0); // a secondary write is necessary for the SPI clk and CS~ to activate during reading. any value can be written.
// HWREG(SSI1_BASE + SSI_O_DR) = ((0xE << 3) | 0b000);
SSIreadStatus = SSIDataGetNonBlocking(SSI1_BASE, &data);
// data = HWREG(SSI1_BASE + SSI_O_DR); // read-command on register level (vs. TivaWare)
printf("Pass %d - EMI_CTRL register value: %d\n", count, data);
printf("SSIreadStatus: %d\n\n", SSIreadStatus);
++count;
}
SysCtlDelay(g_ui32SysClock / 250 / 3);
}
}
I'm a bit clueless at this point. Does anyone have an idea what I might be doing wrong?