Part Number:MSP430G2553
Tool/software: Linux
Hi all
I am new to MSP430G2553. These days I am working on connecting MSP4302553 to Jetson TX2(ubuntu 16.04 ) with SPI interface. The MSP430G2553 is Slave and Jetson TX2 is master.
Here is my question:
1. I tried to use 3-wire spi slave mode without SET, I am not sure whether my code is right for configuration of SPI. The master SPI of Jetson TX2 part is SPI MODE 0 which is CPOL=0, CPHA=0. I have tired the demo code " msp430g2xx3_usci_spi_standard_slave", and I did some change, here below will show details. Also I will put the linux code part.
2. Pls help me check if I use 3-wire SPI mode, whether the hardware connection is right(without Chip select):
Jetson TX2 MSP430G2553
MOSI || P1.2 (UCA0SIMO)
MISO || P1.1 (UCA0SOMI)
SCLK || P1.4 (UCA0CLK)
3. The configuration of master SPI is 8bits,1MHz,mode_0, LSB first. The configuration of Slave SPI is 3-pin, slave mode ,UCCKPH,UCMSB,UCSYNC. I am confused that whether the SYNC mode is necessary.
4.Here below is MSP430G2553 code:
//******************************************************************************
// MSP430G2xx3 Demo - USCI_A0, SPI 3-Wire Slave multiple byte RX/TX
//
// Description: SPI master communicates to SPI slave sending and receiving
// 3 different messages of different length. SPI slave will enter LPM0
// while waiting for the messages to be sent/receiving using SPI interrupt.
// ACLK = NA, MCLK = SMCLK = DCO 16MHz.
//
//
// MSP430G2553
// -----------------
// /|\ | P2.2|<- Master's GPIO (Chip Select)
// | | |
// ---|RST RST |<- Master's GPIO (To reset slave)
// | |
// | P1.2|<- Data In (UCA0SIMO)
// | |
// | P1.1|-> Data Out (UCA0SOMI)
// | |
// | P1.4|<- Serial Clock In (UCA0CLK)
//
// Nima Eskandari
// Texas Instruments Inc.
// April 2017
// Built with CCS V7.0
//******************************************************************************
#include <msp430.h>
#include <stdint.h>
//******************************************************************************
// Example Commands ************************************************************
//******************************************************************************
#define DUMMY 0xFF
/* CMD_TYPE_X_SLAVE are example commands the master sends to the slave.
* The slave will send example SlaveTypeX buffers in response.
*
* CMD_TYPE_X_MASTER are example commands the master sends to the slave.
* The slave will initialize itself to receive MasterTypeX example buffers.
* */
#define DEV_ID 0x01
#define DEV_ACC 0x02
#define DEV_REALTIME 0x03
#define TYPE_0_LENGTH 1
#define TYPE_1_LENGTH 2
#define TYPE_2_LENGTH 6
#define MAX_BUFFER_SIZE 6
/* MasterTypeX are example buffers initialized in the master, they will be
* sent by the master to the slave.
* SlaveTypeX are example buffers initialized in the slave, they will be
* sent by the slave to the master.
* */
uint8_t SlaveType2 [6];
uint8_t SlaveType0 [1];
//******************************************************************************
// General SPI State Machine ***************************************************
//******************************************************************************
typedef enum SPI_ModeEnum{
SPI_TX_REG_ADDRESS_MODE,
SPI_RX_REG_ADDRESS_MODE,
SPI_TX_DATA_MODE,
SPI_RX_DATA_MODE,
SPI_TIMEOUT_MODE
} SPI_Mode;
/* Used to track the state of the software state machine*/
SPI_Mode SlaveMode = SPI_RX_REG_ADDRESS_MODE;
/* The Register Address/Command to use*/
uint8_t ReceiveRegAddr = 0;
/* ReceiveBuffer: Buffer used to receive data in the ISR
* RXByteCtr: Number of bytes left to receive
* ReceiveIndex: The index of the next byte to be received in ReceiveBuffer
* TransmitBuffer: Buffer used to transmit data in the ISR
* TXByteCtr: Number of bytes left to transfer
* TransmitIndex: The index of the next byte to be transmitted in TransmitBuffer
* */
uint8_t ReceiveBuffer[MAX_BUFFER_SIZE] = {0};
uint8_t RXByteCtr = 0;
uint8_t ReceiveIndex = 0;
uint8_t TransmitBuffer[MAX_BUFFER_SIZE] = {0};
uint8_t TXByteCtr = 0;
uint8_t TransmitIndex = 0;
/* Initialized the software state machine according to the received cmd
*
* cmd: The command/register address received
* */
void SPI_Slave_ProcessCMD(uint8_t cmd);
/* The transaction between the slave and master is completed. Uses cmd
* to do post transaction operations. (Place data from ReceiveBuffer
* to the corresponding buffer based in the last received cmd)
*
* cmd: The command/register address corresponding to the completed
* transaction
*/
void SPI_Slave_TransactionDone(uint8_t cmd);
void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count);
void SendUCA0Data(uint8_t val);
void SendUCA0Data(uint8_t val)
{
while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = val;
}
void SPI_Slave_ProcessCMD(uint8_t cmd)
{
ReceiveIndex = 0;
TransmitIndex = 0;
RXByteCtr = 0;
TXByteCtr = 0;
// tx2 上可以用到的cmd指令
switch (cmd)
{
case (DEV_ID): //Send slave device id (This device's id)
SlaveMode = SPI_TX_DATA_MODE;
TXByteCtr = 1;
//Fill out the TransmitBuffer
//CopyArray(SlaveType0, TransmitBuffer, 1);
TransmitBuffer[0] = 0xAD;
//Send First Byte
SendUCA0Data(TransmitBuffer[TransmitIndex++]);
//TXByteCtr--;
break;
case (DEV_ACC): //Send slave device acc value xyz 6-byte
SlaveMode = SPI_TX_DATA_MODE;
TXByteCtr = 6;
//Fill out the TransmitBuffer
CopyArray(SlaveType2, TransmitBuffer, 6);
//Send First Byte
SendUCA0Data(TransmitBuffer[TransmitIndex++]);
TXByteCtr--;
break;
case (DEV_REALTIME): //Send slave device real time clock
SlaveMode = SPI_TX_DATA_MODE;
TXByteCtr = 1;
//Fill out the TransmitBuffer
CopyArray(SlaveType0, TransmitBuffer, 1);
//Send First Byte
SendUCA0Data(TransmitBuffer[TransmitIndex++]);
TXByteCtr--;
break;
default:
__no_operation();
break;
}
}
void SPI_Slave_TransactionDone(uint8_t cmd)
{
switch (cmd)
{
case (DEV_ID): //Slave device id was sent(This device's id)
break;
case (DEV_ACC): //Slave device time was sent(This device's time)
break;
case (DEV_REALTIME): //Send slave device location (This device's location)
break;
default:
__no_operation();
break;
}
}
void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count)
{
uint8_t copyIndex = 0;
for (copyIndex = 0; copyIndex < count; copyIndex++)
{
dest[copyIndex] = source[copyIndex];
}
}
//******************************************************************************
// Device Initialization *******************************************************
//******************************************************************************
void initClockTo1MHz()
{
if (CALBC1_1MHZ==0xFF) // If calibration constant erased
{
while(1); // do not load, trap CPU!!
}
DCOCTL = 0; // Select lowest DCOx and MODx settings
BCSCTL1 = CALBC1_1MHZ; // Set DCO
DCOCTL = CALDCO_1MHZ;
}
void initGPIO()
{
//SPI Pins
P1SEL = BIT1 + BIT2 + BIT4;
P1SEL2 = BIT1 + BIT2 + BIT4;
}
void initSPI()
{
UCA0CTL1 = UCSWRST; // **Put state machine in reset**
UCA0CTL0 |= UCMSB+UCCKPH+UCSYNC+UCMODE_2; // 4-pin, 8-bit SPI Slave,LSB
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
IE2 |= UCA0RXIE; // Enable USCI0 RX interrupt
IE2 |= UCB0TXIE;
}
//******************************************************************************
// Main ************************************************************************
// Enters LPM0 and waits for SPI interrupts. The data sent from the master is *
// then interpreted and the device will respond accordingly *
//******************************************************************************
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
while (!(P1IN & BIT4)); // If clock sig from mstr stays low,
// it is not yet in SPI mode
initClockTo1MHz();
initGPIO();
initSPI();
__bis_SR_register(LPM0_bits + GIE); // Enter LPM4, enable interrupts
__no_operation();
return 0;
}
//******************************************************************************
// SPI Interrupt ***************************************************************
//******************************************************************************
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR (void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCIAB0RX_VECTOR))) USCI0RX_ISR (void)
#else
#error Compiler not supported!
#endif
{
if (IFG2 & UCA0RXIFG)
{
unsigned char uca0_rx_val = UCA0RXBUF;
switch (SlaveMode)
{
case (SPI_RX_REG_ADDRESS_MODE): //INIT STATE MACHINE STATUS
ReceiveRegAddr = uca0_rx_val;
SPI_Slave_ProcessCMD(ReceiveRegAddr);
break;
case (SPI_RX_DATA_MODE):
ReceiveBuffer[ReceiveIndex++] = uca0_rx_val;
RXByteCtr--;
if (RXByteCtr == 0)
{
//Done Receiving MSG
SlaveMode = SPI_RX_REG_ADDRESS_MODE;
SPI_Slave_TransactionDone(ReceiveRegAddr);
}
break;
case (SPI_TX_DATA_MODE):
if (TXByteCtr > 0)
{
SendUCA0Data(TransmitBuffer[TransmitIndex++]);
TXByteCtr--;
}
if (TXByteCtr == 0)
{
//Done Transmitting MSG
SlaveMode = SPI_RX_REG_ADDRESS_MODE;
SPI_Slave_TransactionDone(ReceiveRegAddr);
}
break;
default:
__no_operation();
break;
}
}
}
5. Here below is Jetson TX2 code:
/*
* SPI testing utility (using spidev driver)
*
* Copyright (c) 2007 MontaVista Software, Inc.
* Copyright (c) 2007 Anton Vorontsov <avorontsov@ru.mvista.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* Cross-compile with cross-gcc -I/path/to/cross-kernel/include
*/
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
static void pabort(const char *s)
{
perror(s);
abort(); // abort()是使异常程序终止,同时发送SIGABRT信号给调用进程
}
static const char *device = "/dev/spidev4.0";
static uint8_t mode;
static uint8_t bits = 8;
static uint32_t speed = 48000000;
static uint16_t delay;
static void transfer(int fd)
{
int ret;
uint8_t tx[] = {0x31, 0x32};
uint8_t rx[ARRAY_SIZE(tx)] = {0, }; //the comma here doesn't matter, tested by Tom Xue
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = ARRAY_SIZE(tx),
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits, //important, bits = 8 means byte transfer is possible
};
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
pabort("can't send spi message\n");
printf("the received data is below:\n");
for (ret = 0; ret < ARRAY_SIZE(tx); ret++) { //print the received data, by Tom Xue
if (!(ret % 6))
puts("");
printf("%.2X ", rx[ret]);
}
puts("");
}
int main(int argc, char *argv[])
{
int ret = 0;
int fd;
fd = open(device, O_RDWR);
if (fd < 0)
pabort("can't open device\n");
/*
* spi mode
*/
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1)
pabort("can't set spi mode\n");
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
if (ret == -1)
pabort("can't get spi mode\n");
/*
* bits per word
*/
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't set bits per word\n");
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't get bits per word\n");
/*
* max speed hz
*/
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't set max speed hz\n");
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't get max speed hz\n");
printf("open device: %s\n", device);
printf("set spi mode: %d\n", mode);
printf("set bits per word: %d\n", bits);
printf("set max speed: %d Hz (%d MHz)\n", speed, speed/1000000);
transfer(fd);
close(fd);
return ret;
}
Many thanks
Lee