I have been able to get the correct response to the daisy chain initialization sequence using the MSP430 SPI and the MAX17841 (Table 10) connected to one MAX17853. Wake up and HELLO ALL transactions receive the correct responses on the MISO line, I get a device address that is returned as 0x001. This is the same as the Maxim evaluation GUI. These MSP430 SPI responses have been captured on the scope.
Now, I need to get Table 11 from MAX17841 working. I sent out transaction 1, 2, and 3 (WriteAll_transactions[0].Data[0] = 0xc0; WriteAll_transactions[1].Data[0] = 0xb0; WriteAll_transactions[2].Data[0] = 0x01;) but I don't get the receive of 0x12. Instead I get a 0x11 (sometimes 0x21) which means there is an RX_Overflow_Status or there is unread data. I don't understand why this is. The commands 0xC0 and 0xB0 worked fine in the transactions from Table 10. With the evaluation GUI, Table 11 works fine. So something is missing from the MSP430 handshaking. I appreciate any pointers. I have attached my current file to this post.
I tried including and removing the PEC byte from WriteAll_transactions[0] without any difference in slave response.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <driverlib.h>
#include <intrinsics.h>
#include <msp430.h>
#include "clock~.h" // Clock configurations
#define UART_TRANSMIT_BUFFER_LENGTH 76
#define UART_TXD_PORT GPIO_PORT_P1
#define UART_TXD_PIN GPIO_PIN4
#define UART_RXD_PORT GPIO_PORT_P1
#define UART_RXD_PIN GPIO_PIN5
#define UART_SELECT_FUNCTION GPIO_PRIMARY_MODULE_FUNCTION
#define SPI_MOSI_PORT GPIO_PORT_P2
#define SPI_MOSI_PIN GPIO_PIN6
#define SPI_MISO_PORT GPIO_PORT_P2
#define SPI_MISO_PIN GPIO_PIN5
#define SPI_CLK_PORT GPIO_PORT_P2
#define SPI_CLK_PIN GPIO_PIN4
#define SPI_SELECT_FUNCTION GPIO_PRIMARY_MODULE_FUNCTION
typedef struct {
uint8_t Len;
uint8_t Data[10];
} spi_MaximTrans_t;
static uint8_t RXData[8] = {0}; //SPI receive byte
/**
* Initialize system clocks
*/
static void init_clock(void) {
// Configure one FRAM waitstate as required by the device datasheet for MCLK
// operation beyond 8MHz _before_ configuring the clock system.
FRAMCtl_configureWaitStateControl(FRAMCTL_ACCESS_TIME_CYCLES_1);
//Set DCO FLL reference = REFO
CS_initClockSignal(CS_FLLREF, CS_REFOCLK_SELECT, CS_CLOCK_DIVIDER_1);
//Set ACLK = REFO
CS_initClockSignal(CS_ACLK, CS_REFOCLK_SELECT, CS_CLOCK_DIVIDER_1);
CS_initFLLParam param = {0};
//Set Ratio/Desired MCLK Frequency, initialize DCO, save trim values
CS_initFLLCalculateTrim(CS_MCLK_DESIRED_FREQUENCY_IN_KHZ, CS_MCLK_FLLREF_RATIO, ¶m);
//Set MCLK = REFO
CS_initClockSignal(CS_MCLK, CS_REFOCLK_SELECT, CS_CLOCK_DIVIDER_1);
//Set SMCLK = DCO
CS_initClockSignal(CS_SMCLK, CS_DCOCLKDIV_SELECT, CS_CLOCK_DIVIDER_1);
//Clear all OSC fault flag
CS_clearAllOscFlagsWithTimeout(1000);
}
/**
* Initialize all of the IO pins per their configuration
*/
static void init_gpio(void) {
// Set all GPIO pins to output low to prevent floating input and reduce power consumption
GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN_ALL8);
GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN_ALL8);
GPIO_setOutputLowOnPin(GPIO_PORT_P3, GPIO_PIN_ALL8);
GPIO_setOutputLowOnPin(GPIO_PORT_P4, GPIO_PIN_ALL8);
GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN_ALL8);
GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN2);
GPIO_setAsOutputPin( GPIO_PORT_P1, GPIO_PIN_ALL8);
GPIO_setAsOutputPin( GPIO_PORT_P2, GPIO_PIN_ALL8);
GPIO_setAsOutputPin( GPIO_PORT_P3, GPIO_PIN_ALL8);
GPIO_setAsOutputPin( GPIO_PORT_P4, GPIO_PIN_ALL8);
GPIO_setAsOutputPin( GPIO_PORT_P5, GPIO_PIN_ALL8);
GPIO_setAsOutputPin( GPIO_PORT_P6, GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN2);
}
/*
* Initialize the SPI peripheral on EUSCI A1
*/
void init_spi_peripheral()
{
GPIO_setAsPeripheralModuleFunctionOutputPin(SPI_MOSI_PORT, SPI_MOSI_PIN, SPI_SELECT_FUNCTION);
GPIO_setAsPeripheralModuleFunctionInputPin(SPI_MISO_PORT, SPI_MISO_PIN, SPI_SELECT_FUNCTION);
GPIO_setAsPeripheralModuleFunctionOutputPin(SPI_CLK_PORT, SPI_CLK_PIN, SPI_SELECT_FUNCTION);
//Initialize Master
EUSCI_A_SPI_initMasterParam param = {0};
param.selectClockSource = EUSCI_A_SPI_CLOCKSOURCE_SMCLK;
param.clockSourceFrequency = CS_getSMCLK();
param.desiredSpiClock = 1000000;
param.msbFirst = UCMSB;
param.clockPhase = EUSCI_A_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT;
param.clockPolarity = EUSCI_A_SPI_CLOCKPOLARITY_INACTIVITY_LOW;
param.spiMode = EUSCI_A_SPI_3PIN;
EUSCI_A_SPI_initMaster(EUSCI_A1_BASE, ¶m);
EUSCI_A_SPI_enable(EUSCI_A1_BASE);
}
void init_wd_bms_uart(void)
{
// Configure UART @38400 baud (EUSCI/16MHz)
// http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430BaudRateConverter/index.html
// Configure UCA0TXD and UCA0RXD
GPIO_setAsPeripheralModuleFunctionOutputPin(UART_TXD_PORT, UART_TXD_PIN, UART_SELECT_FUNCTION);
GPIO_setAsPeripheralModuleFunctionInputPin(UART_RXD_PORT, UART_RXD_PIN, UART_SELECT_FUNCTION);
EUSCI_A_UART_initParam param = {
.clockPrescalar = 26, .firstModReg = 0, .secondModReg = 214,
.selectClockSource = EUSCI_A_UART_CLOCKSOURCE_SMCLK,
.parity = EUSCI_A_UART_NO_PARITY,
.msborLsbFirst = EUSCI_A_UART_LSB_FIRST,
.numberofStopBits = EUSCI_A_UART_ONE_STOP_BIT,
.uartMode = EUSCI_A_UART_MODE,
.overSampling = EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION
};
if(STATUS_FAIL == EUSCI_A_UART_init(EUSCI_A0_BASE, ¶m))
{
return;
}
EUSCI_A_UART_enable(EUSCI_A0_BASE);
}
/**
* UART_Transmit_String()
* Prints a null terminated string on the UART
* @param str null terminated string
*/
void UART_Transmit_String(const char *str)
{
int i = 0;
for(i = 0; i < UART_TRANSMIT_BUFFER_LENGTH; i++)
{
if (str[i] != '\0')
{
while (EUSCI_A_UART_queryStatusFlags(EUSCI_A0_BASE, EUSCI_A_UART_BUSY));
EUSCI_A_UART_transmitData(EUSCI_A0_BASE, str[i]);
}
else
{
break;
}
}
}
void SetUpDCInitTransactions(spi_MaximTrans_t DCInit_transactions[]){
//Enable keep alive mode
DCInit_transactions[0].Len = 2;
DCInit_transactions[0].Data[0] = 0x10;
DCInit_transactions[0].Data[1] = 0x5;
//Read Back Transaction byte
DCInit_transactions[1].Len = 2;
DCInit_transactions[1].Data[0] = 0x11;
DCInit_transactions[1].Data[1] = 0x0;
//Enable Rx Interrupt flags
DCInit_transactions[2].Len = 2;
DCInit_transactions[2].Data[0] = 0x4;
DCInit_transactions[2].Data[1] = 0x89;
//No Receive
//Read Back Transaction byte
DCInit_transactions[3].Len = 2;
DCInit_transactions[3].Data[0] = 0x5;
DCInit_transactions[3].Data[1] = 0x0;
//Clear receive buffer
DCInit_transactions[4].Len = 1;
DCInit_transactions[4].Data[0] = 0xe0;
//No Receive
//Wakeup UART slave devices
DCInit_transactions[5].Len = 2;
DCInit_transactions[5].Data[0] = 0x0e;
DCInit_transactions[5].Data[1] = 0x30;
//No Receive
//Read Back Transaction byte
DCInit_transactions[6].Len = 2;
DCInit_transactions[6].Data[0] = 0x0f;
DCInit_transactions[6].Data[1] = 0x0;
//No Receive
//2ms delay for each slave to wake up
//Wait for all UART slave devices to wake up
DCInit_transactions[7].Len = 2;
DCInit_transactions[7].Data[0] = 0x01;
DCInit_transactions[7].Data[1] = 0x0;
//Receive of 0x21 expected
//End of UART slave device wake-up period
DCInit_transactions[8].Len = 2;
DCInit_transactions[8].Data[0] = 0x0e;
DCInit_transactions[8].Data[1] = 0x10;
//Read Back Transaction byte
DCInit_transactions[9].Len = 2;
DCInit_transactions[9].Data[0] = 0x0f;
DCInit_transactions[9].Data[1] = 0x0;
//No Receive
//2ms delay for each slave to report null message
//Wait for null message to be received
DCInit_transactions[10].Len = 2;
DCInit_transactions[10].Data[0] = 0x01;
DCInit_transactions[10].Data[1] = 0x0;
//Receive 0x10 or 0x12
//Clear transmit buffer
DCInit_transactions[11].Len = 1;
DCInit_transactions[11].Data[0] = 0x20;
//No Receive
//Clear receive buffer
DCInit_transactions[12].Len = 1;
DCInit_transactions[12].Data[0] = 0xe0;
//No Receive
//Load the HELLOALL command sequence into the load queue
DCInit_transactions[13].Len = 5;
DCInit_transactions[13].Data[0] = 0xc0;
DCInit_transactions[13].Data[1] = 0x03; //message length
DCInit_transactions[13].Data[2] = 0x57; //HELLOALL command byte
DCInit_transactions[13].Data[3] = 0x0; //Register address (0x00)
DCInit_transactions[13].Data[4] = 0x0; //Initialization address of HELLOALL
//Verify contents of the load queue
DCInit_transactions[14].Len = 5;
DCInit_transactions[14].Data[0] = 0xc1;
DCInit_transactions[14].Data[1] = 0x0;
DCInit_transactions[14].Data[2] = 0x0;
DCInit_transactions[14].Data[3] = 0x0;
DCInit_transactions[14].Data[4] = 0x0;
//Transmit HELLOALL sequence
DCInit_transactions[15].Len = 1;
DCInit_transactions[15].Data[0] = 0xb0;
//No Receive
//2ms delay for each slave to respond
//Poll RX_Stop_Status Bit
DCInit_transactions[16].Len = 2;
DCInit_transactions[16].Data[0] = 0x01;
DCInit_transactions[16].Data[1] = 0x0;
//Receive 0x12
//Service receive buffer. Read the HELLOALL message that propagated through the daisy chain
//and was returned back to the ASCI.The host should verify the device count
DCInit_transactions[17].Len = 4;
DCInit_transactions[17].Data[0] = 0x93;
DCInit_transactions[17].Data[1] = 0x0;
DCInit_transactions[17].Data[2] = 0x0;
DCInit_transactions[17].Data[3] = 0x0;
//Check for receive buffer errors
DCInit_transactions[18].Len = 0x09;
DCInit_transactions[18].Data[0] = 0x0;
}
SPI_Send(spi_MaximTrans_t Transmit[], uint8_t index){
uint8_t SPI_TX_index = 0; //byte count in transaction
GPIO_setOutputLowOnPin(GPIO_PORT_P3, GPIO_PIN1); //Maxim chip select low
__delay_cycles(1000); //idle time between CS change
for(SPI_TX_index = 0; SPI_TX_index < Transmit[index].Len; SPI_TX_index++){
while(!(UCA1IFG & UCTXIFG));
UCA1TXBUF = Transmit[index].Data[SPI_TX_index];
while (!(UCA1IFG & UCRXIFG));
RXData[SPI_TX_index] = UCA1RXBUF;
}
return;
}
/**
* main.c
*/
int main(void)
{
static uint8_t TXData = 0; //transaction count
static spi_MaximTrans_t DCInit_transactions[19];
static spi_MaximTrans_t WriteAll_transactions[3];
static spi_MaximTrans_t ReadAll_transactions[3];
static uint8_t noReceive = 0;
static uint8_t noInc = 0;
char buf[76];
WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
init_clock();
init_gpio(); // Set up IO pins
GPIO_setOutputHighOnPin(GPIO_PORT_P3, GPIO_PIN1); //SPI slave chip select
// Set P1.0 to output direction
GPIO_setAsOutputPin (GPIO_PORT_P1, GPIO_PIN0);
GPIO_setAsInputPinWithPullUpResistor (GPIO_PORT_P4, GPIO_PIN2);
GPIO_enableInterrupt (GPIO_PORT_P4, GPIO_PIN2);
GPIO_selectInterruptEdge (GPIO_PORT_P4, GPIO_PIN2, GPIO_HIGH_TO_LOW_TRANSITION);
GPIO_clearInterrupt (GPIO_PORT_P4, GPIO_PIN2);
GPIO_setAsOutputPin (GPIO_PORT_P6, GPIO_PIN2);
PMM_unlockLPM5();
__enable_interrupt();
SetUpDCInitTransactions(DCInit_transactions);
TXData = 0x0; // Holds transaction number
// Setup peripheral(s) now that gpio and clocks are setup
init_spi_peripheral(); // Init Maxim spi peripheral
init_wd_bms_uart();
GPIO_setOutputHighOnPin (GPIO_PORT_P6, GPIO_PIN2); //SHDNL held high for 4ms to ensure all slaves are powered on
__delay_cycles(32000);
while (TXData < 19){
noInc = 0;
SPI_Send(DCInit_transactions, TXData);
if ((TXData == 6) || (TXData == 9) || (TXData == 15))
__delay_cycles(32000); //wait for slaves to wake up
if (TXData == 7){
if (RXData[DCInit_transactions[7].Len-1] == 0x21){
TXData++;
noReceive = 0;
noInc = 1;
sprintf(buf, "Wake Up status 0x21 received\n\r");
UART_Transmit_String(buf);
}
if (RXData[DCInit_transactions[7].Len-1] != 0x21){
TXData = 7;
noReceive++;
if (noReceive == 3){
sprintf(buf, "Wakeup Error\n\r"); //Need to set a Fault
UART_Transmit_String(buf);
}
}
}
if (TXData == 10){
if ((RXData[DCInit_transactions[10].Len-1] == 0x10) || (RXData[DCInit_transactions[10].Len-1] == 0x12)){
TXData++;
noReceive = 0;
noInc = 1;
sprintf(buf, "Wakeup Successful\n\r");
UART_Transmit_String(buf);
}
else{
TXData = 10;
noReceive++;
if (noReceive == 3){
sprintf(buf, "Wakeup Error: Preamble not received\n\r"); //Need to set a Fault
UART_Transmit_String(buf);
}
}
}
if (TXData == 16){
if ((RXData[DCInit_transactions[16].Len-1] == 0x12)){
TXData++;
noReceive = 0;
noInc = 1;
sprintf(buf, "HELLOALL successful\n\r");
UART_Transmit_String(buf);
}
else{
TXData = 16;
noReceive++;
if (noReceive == 3){
sprintf(buf, "Wakeup Error: Preamble not received\n\r"); //Need to set a Fault
UART_Transmit_String(buf);
}
}
}
if ((noReceive == 0) && !noInc){
TXData++;
}
if (TXData < 19){
GPIO_setOutputHighOnPin(GPIO_PORT_P3, GPIO_PIN1); //Maxim chip select high
__delay_cycles(1000); //idle time between CS change
}
}
GPIO_setOutputHighOnPin(GPIO_PORT_P3, GPIO_PIN1); //Maxim chip select high
__delay_cycles(1000); //idle time between CS change
//Load WRITEALL sequence into the load queue
WriteAll_transactions[0].Len = 7;
WriteAll_transactions[0].Data[0] = 0xc0; //WR_LD_Q_SPI command byte
WriteAll_transactions[0].Data[1] = 5;
WriteAll_transactions[0].Data[2] = 0x02; //WRITEALL
WriteAll_transactions[0].Data[3] = 0x12; //ADDRESS
WriteAll_transactions[0].Data[4] = 0xb1;
WriteAll_transactions[0].Data[5] = 0xb2;
WriteAll_transactions[0].Data[6] = 0Xc4; //PEC byte
// WriteAll_transactions[0].Data[7] = 0x0; //alive counter byte
SPI_Send(WriteAll_transactions, 0);
GPIO_setOutputHighOnPin(GPIO_PORT_P3, GPIO_PIN1); //Maxim chip select high
__delay_cycles(1000); //idle time between CS change
//Start transmitting the WRITEALL sequence from the transmit queue
WriteAll_transactions[1].Len = 1;
WriteAll_transactions[1].Data[0] = 0xb0; //WR_NXT_LD_Q_SPI command byte
SPI_Send(WriteAll_transactions, 1);
__delay_cycles(32000);
GPIO_setOutputHighOnPin(GPIO_PORT_P3, GPIO_PIN1); //Maxim chip select high
__delay_cycles(1000); //idle time between CS change
WriteAll_transactions[2].Len = 2;
WriteAll_transactions[2].Data[0] = 0x01; //Read RX_Status register
WriteAll_transactions[2].Data[1] = 0x0;
noReceive = 1;
while ((noReceive > 0) && (noReceive < 3)){
SPI_Send(WriteAll_transactions, 2);
if (RXData[WriteAll_transactions[2].Len-1] == 0x12){
sprintf(buf, "WRITEALL acknowledged\n\r");
UART_Transmit_String(buf);
noReceive = 0;
}
else{
noReceive++;
GPIO_setOutputHighOnPin(GPIO_PORT_P3, GPIO_PIN1); //Maxim chip select high
__delay_cycles(1000); //idle time between CS change
if (noReceive == 3){
sprintf(buf, "Writeall Error: not acknowledged\n\r"); //Need to set a Fault
UART_Transmit_String(buf);
}
}
}
GPIO_setOutputHighOnPin(GPIO_PORT_P3, GPIO_PIN1); //Maxim chip select high
__delay_cycles(1000); //idle time between CS change
ReadAll_transactions[0].Len = 7;
ReadAll_transactions[0].Data[0] = 0x93;
ReadAll_transactions[0].Data[1] = 0x0;
ReadAll_transactions[0].Data[2] = 0x0;
ReadAll_transactions[0].Data[3] = 0x0;
ReadAll_transactions[0].Data[4] = 0x0;
ReadAll_transactions[0].Data[5] = 0x0;
ReadAll_transactions[0].Data[6] = 0x0;
SPI_Send(ReadAll_transactions, 0);
GPIO_setOutputHighOnPin(GPIO_PORT_P3, GPIO_PIN1); //Maxim chip select high
__delay_cycles(1000); //idle time between CS change
ReadAll_transactions[1].Len = 2;
ReadAll_transactions[1].Data[0] = 0x09;
ReadAll_transactions[1].Data[1] = 0x0;
SPI_Send(ReadAll_transactions, 0);
GPIO_setOutputHighOnPin(GPIO_PORT_P3, GPIO_PIN1); //Maxim chip select high
__delay_cycles(1000); //idle time between CS change
}
//******************************************************************************
//
//This is the PORT2_VECTOR interrupt vector service routine
//
//******************************************************************************
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=PORT4_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(PORT2_VECTOR)))
#endif
void P4_ISR (void)
{
GPIO_clearInterrupt (GPIO_PORT_P4, GPIO_PIN2);
// Toggle P1.0 output
GPIO_toggleOutputOnPin (GPIO_PORT_P1, GPIO_PIN0);
GPIO_setOutputHighOnPin(GPIO_PORT_P3, GPIO_PIN1);
}




