After configuring SPI communication for SAMD51 enable function freezes the setup - c++

I am currently working to configurate SPI communication in a SAMD51 board. After a lot of research I could find how to setup the registers to start the pin configuration and clock setup, among other things. But there is one procedure in the end of the setup that requires to enable the pin again.
Here is the datasheet for the MCU https://www.mouser.com/datasheet/2/268/60001507A-1130176.pdf
SERCOM4->SPI.CTRLA.bit.ENABLE = 1;
After I call this line the library freezes and I cannot get any other response.
find bellow the cpp file.
#include "SercomSPISlave.h"
// Constructors //
SercomSPISlave::SercomSPISlave()
{
}
// Public Methods //
void SercomSPISlave::Sercom4init()
{
//Setting up NVIC
NVIC_EnableIRQ(SERCOM4_0_IRQn);
NVIC_SetPriority(SERCOM4_0_IRQn,2);
//MCLK->APBDMASK.reg |= MCLK_APBDMASK_SERCOM4;
MCLK->APBDMASK.bit.SERCOM4_ = 1;
//Setting Generic Clock Controller!!!!
//GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(GCM_SERCOM4_CORE) | //Generic Clock 0
// GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is the source
// GCLK_CLKCTRL_CLKEN; // Enable Generic Clock Generator
GCLK->PCHCTRL[34].reg = GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN;
//while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); //Wait for synchronisation
//Configure SERCOM4 SPI PINS
//Set PA12 as input (MOSI) - on D22 / MISO
//Set PB09 as input (SCK) - on A2
//Set PB10 as input (SS) - on D23 / MOSI
//Set PB11 as output (MISO) - on D24 / SCK
PORT->Group[PORTB].PINCFG[11].bit.PMUXEN = 0x1; //Enable Peripheral Multiplexing for SERCOM4 SPI PB11
PORT->Group[PORTB].PMUX[11 >> 1].bit.PMUXO = 0x3; //SERCOM 4 is selected for peripheral use of this pad (0x3 selects peripheral function D: SERCOM-ALT)
PORT->Group[PORTB].PINCFG[12].bit.PMUXEN = 0x1; //Enable Peripheral Multiplexing for SERCOM4 SPI PB12
PORT->Group[PORTB].PMUX[12 >> 1].bit.PMUXE = 0x3; //SERCOM 4 is selected for peripheral use of this pad (0x3 selects peripheral function D: SERCOM-ALT)
PORT->Group[PORTB].PINCFG[13].bit.PMUXEN = 0x1; //Enable Peripheral Multiplexing for SERCOM4 SPI PB13
PORT->Group[PORTB].PMUX[13 >> 1].bit.PMUXO = 0x3; //SERCOM 4 is selected for peripheral use of this pad (0x3 selects peripheral function D: SERCOM-ALT)
PORT->Group[PORTA].PINCFG[9].bit.PMUXEN = 0x1; //Enable Peripheral Multiplexing for SERCOM4 SPI PB09
PORT->Group[PORTA].PMUX[9 >> 1].bit.PMUXO = 0x3; //SERCOM 4 is selected for peripheral use of this pad (0x3 selects peripheral function D: SERCOM-ALT)
/*
Explanation:
PMUXEN stands for Peripheral Multiplexing Enable
PMUXE stands for Even bits in the Peripheral Multiplexing register
PMUXO stands for Odd bits in the Peripheral Multiplexing register
The selection of peripheral function A to H is done by writing to the Peripheral Multiplexing Odd and Even bits in the Peripheral Multiplexing register (PMUXn.PMUXE/O) in the PORT.
Reference: Atmel-42181G-SAM-D21_Datasheet section 6.1 on page 21
PA12 corresponds to: PORTA, PMUX[6] Even
PB09 corresponds to: PORTB, PMUX[4] Odd
PB10 corresponds to: PORTB, PMUX[5] Even
PB11 corresponds to: PORTB, PMUX[5] Odd
In general:
Px(2n+0/1) corresponds to Portx, PMUX[n] Even=0/Odd=1*/
//Disable SPI 1
SERCOM4->SPI.CTRLA.bit.ENABLE =0;
while(SERCOM4->SPI.SYNCBUSY.bit.ENABLE);
//Reset SPI 1
SERCOM4->SPI.CTRLA.bit.SWRST = 1;
while(SERCOM4->SPI.CTRLA.bit.SWRST || SERCOM4->SPI.SYNCBUSY.bit.SWRST);
//Set up SPI Control A Register
SERCOM4->SPI.CTRLA.bit.DORD = 0; //MSB first
SERCOM4->SPI.CTRLA.bit.CPOL = 0; //SCK is low when idle, leading edge is rising edge
SERCOM4->SPI.CTRLA.bit.CPHA = 0; //data sampled on leading sck edge and changed on a trailing sck edge
SERCOM4->SPI.CTRLA.bit.FORM = 0x0; //Frame format = SPI
SERCOM4->SPI.CTRLA.bit.DIPO = 0x0; //DATA PAD0 MOSI is used as slave input (slave mode) // page 492
SERCOM4->SPI.CTRLA.bit.DOPO = 0x2; //DATA PAD2 MISO is used as slave output
SERCOM4->SPI.CTRLA.bit.MODE = 0x2; //SPI in Slave mode
SERCOM4->SPI.CTRLA.bit.IBON = 0x1; //Buffer Overflow notification
SERCOM4->SPI.CTRLA.bit.RUNSTDBY = 1; //wake on receiver complete
//Set up SPI control B register
//SERCOM4->SPI.CTRLB.bit.RXEN = 0x1; //Enable Receiver
SERCOM4->SPI.CTRLB.bit.SSDE = 0x1; //Slave Selecte Detection Enabled
SERCOM4->SPI.CTRLB.bit.CHSIZE = 0; //character size 8 Bit
//SERCOM4->SPI.CTRLB.bit.PLOADEN = 0x1; //Enable Preload Data Register
//while (SERCOM4->SPI.SYNCBUSY.bit.CTRLB);
//Set up SPI interrupts
SERCOM4->SPI.INTENSET.bit.SSL = 0x1; //Enable Slave Select low interrupt
SERCOM4->SPI.INTENSET.bit.RXC = 0x1; //Receive complete interrupt
SERCOM4->SPI.INTENSET.bit.TXC = 0x1; //Receive complete interrupt
SERCOM4->SPI.INTENSET.bit.ERROR = 0x1; //Receive complete interrupt
SERCOM4->SPI.INTENSET.bit.DRE = 0x1; //Data Register Empty interrupt
//init SPI CLK
//SERCOM4->SPI.BAUD.reg = SERCOM_FREQ_REF / (2*4000000u)-1;
//Enable SPI
SERCOM4->SPI.CTRLB.bit.RXEN = 0x1; //Enable Receiver, this is done here due to errate issue
while(SERCOM4->SPI.SYNCBUSY.bit.CTRLB); //wait until receiver is enabled
Serial.begin(115200);
SERCOM4->SPI.CTRLA.bit.ENABLE = 1;
Serial.print(SERCOM4->SPI.CTRLA.bit.ENABLE);
while(SERCOM4->SPI.SYNCBUSY.bit.ENABLE);
}
Find bellow the .h file.
#ifndef SercomSPISlave_h
#define SercomSPISlave_h
#include <Arduino.h>
class SercomSPISlave
{
public:
// Constructors //
SercomSPISlave();
// Public Methods //
void Sercom4init();
};
#endif
Find bellow the .ino code
#include <SercomSPISlave.h>
SercomSPISlave SPISlave;
void setup()
{
Serial.begin(115200);
Serial.println("Serial started");
SPISlave.Sercom4init();
while(!Serial);
Serial.println("Sercom1 SPI slave initialized!");
}
void loop()
{
}
I appreciate any support you can give me.

Related

LoRa communication between ESP8266 and RPi 3B+

I have an ESP8266 and a RPI 3B+ both equipped with LoRa-02 (SX1278) modules. I'm trying to send a packet from the ESP to the RPi, but it's not working.
Please consider the following code snippet on ESP8266:
main.cpp
#include "loRaComms.h"
void setup() {
// sender
Serial.begin(115200);
initLoRa(434800000);
}
void loop() {
// sender
brodcastBuffer();
delay(1000);
}
loRaComms.cpp
#include <LoRa.h>
void initLoRa(int freq) {
LoRa.setPins(Lora_NSS, Lora_RESET, Lora_DIO0);
LoRa.setFrequency(freq);
LoRa.setSignalBandwidth(62500);
LoRa.setSpreadingFactor(12);
LoRa.setCodingRate4(8);
LoRa.setGain(0);
LoRa.setPreambleLength(6);
if (!LoRa.begin(freq)) {
// initialize ratio at 915 MHz 433E6 - Asia, 866E6 - Europe, 915E6 - North America
Serial.println("LoRa init failed.");
} else {
Serial.println("LoRa init succeeded.");
}
}
void brodcastBuffer() {
LoRa.beginPacket(); // start packet
LoRa.print("hello!");
LoRa.endPacket();
}
I have no problem with the ESP8266 code. I have tested this code with 2 ESP8266, one sender and one receiver, everything is working fine!
Now let's see the RPi 3B+ code. I have used [this repository][1] with its own sample code as follows:
void * rx_f(void *p) {
rxData *rx = (rxData *)p;
printf("rx done \n");
printf("CRC error: %d\n", rx->CRC);
printf("Data size: %d\n", rx->size);
printf("string: %s\n", rx->buf); // Data we've received
printf("RSSI: %d\n", rx->RSSI);
printf("SNR: %f\n", rx->SNR);
free(p);
return NULL;
}
int main() {
LoRa_ctl modem;
// See for typedefs, enumerations and there values in LoRa.h header file
modem.spiCS = 0; // Raspberry SPI CE pin number
modem.rx.callback = rx_f;
modem.eth.preambleLen = 6;
modem.eth.bw = BW62_5; // Bandwidth 62.5KHz
modem.eth.sf = SF12; // Spreading Factor 12
modem.eth.ecr = CR8; // Error coding rate CR4/8
modem.eth.freq = 434800000; // 434.8MHz
modem.eth.resetGpioN = 27; // GPIO4 on lora RESET pin
modem.eth.dio0GpioN = 17; // GPIO17 on lora DIO0 pin to control Rxdone and Txdone interrupts
modem.eth.outPower = OP20; // Output power
modem.eth.powerOutPin = PA_BOOST; // Power Amplifier pin
modem.eth.AGC = 1; // Auto Gain Control
modem.eth.OCP = 240; // 45 to 240 mA. 0 to turn off protection
modem.eth.implicitHeader = 0; // Explicit header mode
modem.eth.syncWord = 0x12;
printf("%d\n", modem.eth.bw);
printf("%d\n", modem.eth.ecr);
// For detail information about SF, Error Coding Rate, Explicit header, Bandwidth, AGC, Over current protection and other features refer to sx127x datasheet https:// www.semtech.com/uploads/documents/DS_SX127$
LoRa_begin(&modem);
LoRa_receive(&modem);
while (1) {
usleep(200000);
}
printf("end\n");
LoRa_end(&modem);
}```
But I can't receive anything on RPi. I also tested the ping pong sample on two RPi 3 and it didn't work.
Did I miss something here? I'm open to use any alternative library on RPi3, but I can only use C/C++ libraries. I've used the following pins:
raspi LoRa
GPIO27, pin13 RESET
GPIO17, pin 11 DIO0
MOSI (GPIO10, pin 19) MOSI
MISO (GPIO9, pin 21) MISO
CLK (GPIO11, pin 23) SCK
SPI_CE0 (GPIO8, pin 24) NSS
[1]: https://%20github.com/YandievRuslan/sx1278-LoRa-RaspberryPi.git
You can check your pin connection
The PI 3 MISO is GPIO09 and MOSI is GPIO10.
So you need change the pin connection to the following
raspi LoRa
MOSI (GPIO10, pin 19) MISO
MISO (GPIO9, pin 21) MOSI
Here is the introduction of SPI MOSI and MISO
https://www.analog.com/en/analog-dialogue/articles/introduction-to-spi-interface.html

MSP430F2418: Unable to set P2.3 pin to high

I am using MSO430F2418 for my project. I am sending Hello world message to Bluetooth module via UART pins. Also I need to set pin P2.3 to high to reset the Bluetooth. Unfortunately Im unable to set that perticuler pin to high. When I check the voltage at Reset pin of Bluetooth it is low.
You can see below two lines in my code. I have used these statements to set the P2.3.
P2DIR|=0x08;
P2OUT|=0x08;
I have attached an image. There you can see the hardware. enter image description here
#include <stdio.h>
#include <msp430.h>
const char string[] = { "Hello World\r\n" };
unsigned int i;
int main(void){
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
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;
P2DIR|=0x08;
P2OUT|=0x08;
P3SEL = 0x30; // P3.4,5 = USCI_A0 TXD/RXD
UCA0CTL1 |= UCSSEL_3; // SMCLK
UCA0BR0 = 8; // 1MHz 115200
UCA0BR1 = 0; // 1MHz 115200
UCA0MCTL = UCBRS2 + UCBRS1; // Modulation UCBRSx = 5
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
// IE2 |= UCA0RXIE; // Enable USCI_A0 RX interrupt
IE2 |= UCA0TXIE;
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0, interrupts enabled
}
#pragma vector=USCIAB0TX_VECTOR
__interrupt void USCI0TX_ISR(void)
{
UCA0TXBUF = string[i++]; // TX next character
if (i == sizeof string - 1){ // TX over?
IE2 &= ~UCA0TXIE; // Disable USCI_A0 TX interrupt
_delay_cycles(1000000);
i = 0;
IE2 |= UCA0TXIE; // Enable USCI_A0 TX interrupt
}
}

Why receiving shifted and duplicated data in SPI communication between Raspberry Pi (master) and Nucleo l432kc boards (slaves)

​I've asked the same question on the ST Q&A forum and on the Raspberry Pi forum, but I didn't receive any answer. I hope that here there is someone that can help me.
I want to make communicate two Nucleo l432kc (slaves) with a Raspberry Pi (master) through the SPI protocol. On the Raspberry I'm using the Spidev API, while on the Nucleo I'm using the HAL SPI interface with DMA.
The only configuration that permits a stable transmission is the SPI_MODE_2 of Spidev that corresponds to the SPI_POLARITY_HIGH and SPI_PHASE_2EDGE configuration of the HAL.
With the above configuration I have two problems:
The messages sent by the master to the slaves arrive always correctly, but all the messages sent by the slaves to the master always arrive shifted by 1 bit on the right (e.g. if I send two bytes 0b00000011 0b00000001 I receive 0b00000001 0b10000000). It seems that the sampling of the MISO signal is delayed but I can't figure out why.
I receive the data on both the slaves regardless if the chip select is set or not. In the response of the slaves I have no collisions so I think that only the MISO bus is effectively set in high impedance mode in the slave when the NSS is high.
To test purpose I've tried to use the SPISlave class of the mbed framework,
this class cannot use the DMA so I can't use it in the real program. Using it I solve the first problem but the second persists.
Another thing that could be useful is that with the SPISlave class I can use all the 4 mode of the SPI protocol, of course the slaves and the master must use the same mode but is not import which one.
As I said before with the HAL interface I can use only the SPI_MODE_2.
This is the configuration code that runs on both the slaves:
// SPI
__HAL_RCC_SPI1_CLK_ENABLE();
/* SPI1 parameter configuration*/
hspi.Instance = SPI1;
hspi.Init.Mode = SPI_MODE_SLAVE;
hspi.Init.Direction = SPI_DIRECTION_2LINES; // full duplex mode
hspi.Init.DataSize = SPI_DATASIZE_8BIT; // dimension of 1 byte
hspi.Init.CLKPolarity = SPI_POLARITY_HIGH; // start and idle clk value
hspi.Init.CLKPhase = SPI_PHASE_2EDGE; // edge of sampling of data both on miso and mosi
hspi.Init.FirstBit = SPI_FIRSTBIT_MSB; // bit order
hspi.Init.TIMode = SPI_TIMODE_DISABLE; // disabling the TI mode
hspi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; // disable crc calc
hspi.Init.NSSPMode = SPI_NSS_PULSE_DISABLE; // disable NSS puls value
if (HAL_SPI_Init(&hspi) != HAL_OK)
return false;
/* SPI1 interrupt Init */
HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(SPI1_IRQn);
// GPIO
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**SPI1 GPIO Configuration
PA1 ------> SPI1_SCK
PA11 ------> SPI1_MISO
PA12 ------> SPI1_MOSI
PB0 ------> SPI1_NSS
*/
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_11|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// DMA
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* SPI1 DMA Init */
/* SPI1_RX Init */
hdma_spi_rx.Instance = DMA1_Channel2;
hdma_spi_rx.Init.Request = DMA_REQUEST_1;
hdma_spi_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi_rx.Init.Mode = DMA_NORMAL;
hdma_spi_rx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_spi_rx) != HAL_OK) return false;
__HAL_LINKDMA(&hspi,hdmarx,hdma_spi_rx);
/* DMA interrupt init */
/* DMA1_Channel2_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
/* SPI1 DMA Init */
/* SPI1_TX Init */
hdma_spi_tx.Instance = DMA1_Channel3;
hdma_spi_tx.Init.Request = DMA_REQUEST_1;
hdma_spi_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi_tx.Init.Mode = DMA_NORMAL;
hdma_spi_tx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_spi_tx) != HAL_OK) return false;
__HAL_LINKDMA(&hspi,hdmatx,hdma_spi_tx);
/* DMA interrupt init */
/* DMA1_Channel3_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
And this is the code that runs on the master:
unsigned int bitsPerByte = 8u;
unsigned int delay = 0u;
unsigned int speed = 100; // hz
unsigned int cs_change = 0u; // false in C
// initialization
fd = ::open("/dev/spidev0.0", O_RDWR);
auto mode = SPI_MODE_2; // clock polarity low, clock phase second edge
if (fd == -1)
throw std::runtime_error("Can't open the spi device");
if (::ioctl(fd, SPI_IOC_WR_MODE, &mode) == -1)
throw std::runtime_error("Can't set the spi mode");
/*
* bits per word
*/
auto bits = bitsPerByte;
auto ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
throw std::runtime_error("can't set bits per word");
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
throw std::runtime_error("can't get bits per word");
/*
* max speed hz
*/
auto maxSpeed = speed;
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &maxSpeed);
if (ret == -1)
throw std::runtime_error("can't set max speed hz");
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &maxSpeed);
if (ret == -1)
throw std::runtime_error("can't get max speed hz");
// code used for sending messages
void transfer(uint8_t *tx, uint8_t *rx, size_t size) {
struct spi_ioc_transfer tr = {
(unsigned long)tx, // .tx_buf
(unsigned long)rx, // .rx_buf
size, // .len
speed, // .speed_hz
delay, // .delay_usecs
bitsPerByte, // .bits_per_word
cs_change, // .cs_change
0, // .tx_nbits
0, // .rx_nbits
0, // .pad
};
if (::ioctl(fd, SPI_IOC_MESSAGE(1), &tr) == -1)
throw std::runtime_error("Can't send data throught the spi");
}
In the main functions of the slaves the only thing that I actually do is to send back the exact packet that I receive.
EDIT
On the forum of the Raspberry someone told me to use piscope to see the digital value that is send on the pins. I've done it and I've seen that the CE0 and CE1 pin are always low. I can't understand why I do not have collisions on the MISO.
EDIT 2
I've solved the second problem (the duplicated data) it was an error on the master configuration, I was using cs_change = 1 but it must be equal to 0.
With piscope I've figured out that the slaves are sending the data correctly, it's the master that does not read them well.

Arduino SPI hangs during transfers

I'm in the middle of a project, and at a loss. I managed to get 2 Arduinos to talk to each other over SPI, but the slave stops during a series of transfers, seemingly without reason.
And what's really disturbing is that if I send more transfers from the master it continues the series, as if it was waiting to continue.
I'm thinking there's some acknowledgement or flag that stops code execution, but I have no idea.
#include <SPI.h>
boolean ack = 0;
#define ACK 2
byte buffer = 0;
byte rx = 0;
bool SSlast = HIGH;
byte clr = 0;
void stat_upd(byte dat, byte ric) {
Serial.println("---------------------------------------------");
Serial.println("Sent:");
Serial.println(dat, HEX);
Serial.println("Received:"); // 0x81 in teoria
Serial.println(ric, HEX);
return;
}
// Initialize SPI slave.
void SlaveInit(void) {
// Initialize SPI pins.
pinMode(SCK, INPUT);
pinMode(MOSI, INPUT);
pinMode(MISO, INPUT);
pinMode(SS, INPUT);
pinMode(ACK, OUTPUT);
// Enable SPI as slave.
SPCR = 0x6F;
clr = SPSR;
clr = SPDR;
SPI.begin();
}
// SPI Transfer.
byte SPItransfer(byte value) {
byte temp = 0;
SPDR = value;
// temp =SPI.transfer(value);
while (!(SPSR & (1 << SPIF)));
digitalWrite(ACK, LOW);
delay(1);
digitalWrite(ACK, HIGH);
delay(10);
return SPDR;
}
// The setup() function runs after reset.
void setup() { ///////////////// setup
Serial.begin(9600);
SlaveInit();
Serial.println("MC Initialized");
}
void loop() { ////////////// loop
// Slave Enabled?
if (!digitalRead(SS)) {
rx = SPItransfer(0x00);
stat_upd(0x00, rx);
rx = SPItransfer(0x08);
stat_upd(0x08, rx);
rx = SPItransfer(0x5a);
stat_upd(0x5a, rx);
rx = SPItransfer(0x5d);
stat_upd(0x5d, rx);
rx = SPItransfer(0x5c);
stat_upd(0x5c, rx);
rx = SPItransfer(0x5d);
stat_upd(0x5d, rx);
rx = SPItransfer(0x04);
stat_upd(0x04, rx);
rx = SPItransfer(0x00);
stat_upd(0x00, rx);
rx = SPItransfer(0x00);
stat_upd(0x00, rx);
rx = SPItransfer(0x80);
stat_upd(0x80, rx);
}
}
This is a bit of a guess, but my guesses wrt Arduino code are correct more often then not.
Check how you are sending the data via the Master.
As per this code, the slave waits for the SS pin to go low, then talks to the SPI and then clears the ack pin for 1 millisecond and then sends the communicaiton data via the serial port to the PC.
The problem I see here is that 1 millisecond is too small of a time frame for the master to detect it correctly.
So my guess is that, you have written the master code in such a manner, that it does not look at the ACK pin. Which means that the master will clear the SS pin, do the communication and then clear the SS pin immediately.
This is an issue because the slave talks to the serial port once this communication is done. Which means that when the master sets the SS pin low again, the slave might be sending data to the serial monitor, and may miss out on the communication altogether.
To fix this you need to change the slave code to continuously talk to the master while the SS pin is low, and only send the data back to the serial monitor when the SS pin becomes high.

Serial communication not working when class is instantiated in Arduino Environment

I'm trying to write code for my Arduino Mega to communicate with ADXL345 accelerometer using c++ style library.
This is my Accelerometer.h file:
#include <Wire.h>
#define ADXL345 (0x53) // I2C Address of ADXL345 accelerometer
struct Acceleration
{
float x;
float y;
float z;
};
class Accelerometer
{
public:
Accelerometer(void); // Constructor
Acceleration readData(void); // Read sensor data
private:
char buffer[6]; // Buffer to store data (x, y, z: LSB and MSB of each)
char DATA_FORMAT; // Address of DATA_FORMAT Register
char POWER_CTL; // Address of POWER_CTL Register
char DATAX0; // Address of X-Axis LSB Data
char DATAX1; // Address of X-Axis MSB Data
char DATAY0; // Address of Y-Axis LSB Data
char DATAY1; // Address of Y-Axis MSB Data
char DATAZ0; // Address of Z-Axis LSB Data
char DATAZ1; // Address of Z-Axis MSB Data
void writeToAccelerometer(char address, char value);
void readFromAccelerometer(char address, int numOfBytes);
};
And this is my Accelerometer.cpp file:
#include "Accelerometer.h"
#include <Wire.h>
Accelerometer::Accelerometer()
{
Wire.begin(); // Initialize I2C bus
writeToAccelerometer(DATA_FORMAT, 0x01); // +/- 4g range
writeToAccelerometer(POWER_CTL, 0x08); // Measurement Mode
DATA_FORMAT = 0x31; // Address of DATA_FORMAT Register
POWER_CTL = 0x2D; // Address of POWER_CTL Register
DATAX0 = 0x32; // Address of X-Axis LSB Data
DATAX1 = 0x33; // Address of X-Axis MSB Data
DATAY0 = 0x34; // Address of Y-Axis LSB Data
DATAY1 = 0x35; // Address of Y-Axis MSB Data
DATAZ0 = 0x36; // Address of Z-Axis LSB Data
DATAZ1 = 0x37; // Address of Z-Axis MSB Data
}
void Accelerometer::writeToAccelerometer(char address, char value)
{
Wire.beginTransmission(ADXL345); // start transmission to ADXL345
Wire.write(address); // send register address
Wire.write(value); // send value to write
Wire.endTransmission(); // end transmission
}
void Accelerometer::readFromAccelerometer(char address, int numOfBytes)
{
Wire.beginTransmission(ADXL345); // start transmission to ADXL345
Wire.write(address); // send register address
Wire.endTransmission(); // end transmission
Wire.beginTransmission(ADXL345); // start transmission to ADXL345
Wire.requestFrom(ADXL345, numOfBytes); // request some bytes from device
int i = 0;
while(Wire.available()) // while there is data
{
buffer[i] = Wire.read(); // receive a byte and save it in the buffer
i++;
}
Wire.endTransmission(); // end transmission
}
Acceleration Accelerometer::readData()
{
Acceleration R;
readFromAccelerometer(DATAX0, 6); // Read data from sensor
// Merge of data and conversion to int format
int x_acceleration = (((int)buffer[1]) << 8) | buffer[0];
int y_acceleration = (((int)buffer[3]) << 8) | buffer[2];
int z_acceleration = (((int)buffer[5]) << 8) | buffer[4];
R.x = x_acceleration*0.0078;
R.y = x_acceleration*0.0078;
R.z = x_acceleration*0.0078;
return R;
}
I'm using this library im my Arduino sketch with this code:
#include <Wire.h>
#include "Accelerometer.h"
Accelerometer accel;
Acceleration Racc;
void setup()
{
Serial.begin(9600); // Start serial for outbut at 9600 bps
}
void loop()
{
Racc = accel.readData();
// Print data
Serial.print("ACCELERATION - X: ");
Serial.print( Racc.x );
Serial.print(" G / Y: ");
Serial.print( Racc.y );
Serial.print(" G / Z: ");
Serial.print( Racc.z );
Serial.print(" G\n");
delay(100);
}
This code is compilated without erros. However, because of the instantiation of Accelerometer class, Serial communication is not working (I can't see any text in Serial Monitor). When I remove the class instance of the code (letting just Serial communication in code), I can see what is print in Serial Monitor.
Does anybody have any idea about what is going on? I would appreciate any help.
As the ADXL345 can operate either SPI or I2C it needs to be configured, as such. In your case of trying to use it as I2C, the CS of the ADXL345 need to be tied to 3.3V
I2C mode is enabled if the CS pinis tied high to VDD I/O. The CS pin
should always be tied high to VDD I/O or be driven by an external
controller because there is nodefault mode if the CS pin is left
unconnected. Therefore, not taking these precautions may result in an
inability to ommunicatewith the part.
Where in your above code I do not see any pins configured as output to drive the CS.
It has been my experience that when the I2C (wire.h) library is not properly connected to a device it can be blocking. Which is similar to your described symptom here.
You may want to reference your code against others, such as https://github.com/jenschr/Arduino-libraries/tree/master/ADXL345. which appears to fully support the many features of the ADXL345 over I2C