Variadic functions not working on arduino - arduino

I'm trying to write my own basic libraries to program the Arduino in pure C++. I've tried using a variadic function to implement something similar to Linux's ioctl() to control the SPI module but it just won't work and I have no idea why. I don't pin 13 (Arduino SCK) light up as expected during SPI transactions indicating that SPI is not operating. All the other functions in my library work properly.
The following is my SPI library:
/*
spi.h: SPI driver for Atmega328p
*/
#ifndef _SPI_H
#define _SPI_H
#include <avr/io.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdarg.h>
#include <inttypes.h>
// SPI bus pin mapping ///////////////////////////////////
#define PORT_SPI PORTB // Port register containing SPI pins
#define DDR_SPI DDRB // Data direction register containing SPI pins
#define DDR_SCK DDB5 // Data direction bit of SPI SCK pin
#define DDR_MISO DDB4 // Data direction bit of SPI MISO pin
#define DDR_MOSI DDB3 // Data direction bit of SPI MOSI pin
#define DDR_HWCS DDB2 // Data direction bit of SPI hardware chip select pin
#define PIN_SCK PB5 // Port register bit of SPI SCK pin
#define PIN_MISO PB4 // Port register bit of SPI MISO pin
#define PIN_MOSI PB3 // Port register bit of SPI MOSI pin
#define PIN_HWCS PB2 // Port register bit of SPI hardware chip select pin
// SPI ioctl commands ////////////////////////////////////
#define SPIIOCCONF 0 // Configure SPI command
#define SPIIOCDECONF 1 // Deconfigure SPI command
#define SPIIOCTRANSMIT 2 // SPI byte exchange command
// Clock frequency settings //////////////////////////////
#define SCK_DIV2 2 // Divide source pulse by 2
#define SCK_DIV4 4 // Divide source pulse by 4
#define SCK_DIV8 8 // Divide source pulse by 8
#define SCK_DIV16 16 // Divide source pulse by 16
#define SCK_DIV32 32 // Divide source pulse by 32
#define SCK_DIV64 64 // Divide source pulse by 64
#define SCK_DIV128 128 // Divide source pulse by 128
// SPI modes /////////////////////////////////////////////
#define SPI_MODE0 0
#define SPI_MODE1 1
#define SPI_MODE2 2
#define SPI_MODE3 3
// SPI transaction data orders ///////////////////////////
#define LSBFIRST 0
#define MSBFIRST 1
// The SPI module ////////////////////////////////////////
class spiModule {
private:
bool configured; // Indicates whether SPI is operating with a valid configuration
uint8_t ddrOld, portOld; // Value of DDR_SPI and PORT_SPI just before an SPI configuration was called for
// ( These variables are used to restore the state of the
// SPI pins when SPI is deconfigured )
/* ioctls used to operate the SPI module */
void spiiocconf(int, int, int); // Configure SPI with a valid clock frequency, data order and SPI mode
void spiiocdeconf(void); // Deconfigure SPI and restore SPI pins to their original states
void spiioctransmit(uint8_t, uint8_t *); // Exchange a byte of data over SPI
/* ioctl handlers */
/* These routines check the validity of the arguments and call the ioctls (above) only if all arguments make sense */
/* I've tested these functions by making them public and found that they work perfectly */
int conf(int, int, int); // call spiiocconf() if arguments are valid and SPI is configured
int deconf(void); // call spiiocdeconf() if all arguments are valid and SPI is configured
int transmit(uint8_t, uint8_t *); // call spiioctransmit() if all arguments are valid and SPI is configured
public:
spiModule(void); // Initialize this class
int ioctl(int action, ... ); // Core ioctl handler (supposed to work like the Linux ioctl() system call). But this one just won't work.
};
spiModule spi; // Object of class spiModule for using SPI
// Constructor ///////////////////////////////////////////
spiModule::spiModule(void) {
configured = false;
}
// Private routines //////////////////////////////////////
/* Ioctls */
void spiModule::spiiocconf(int clkDiv, int dataOrder, int mode) {
// Store the values of DDR_SPI and PORT_SPI so they may be recovered when SPI is deconfigured
ddrOld = DDR_SPI;
portOld = PORT_SPI;
// Configure SCK, MOSI and HWCS as output pins and MISO as an input pin
DDR_SPI |= (_BV(DDR_HWCS) | _BV(DDR_SCK) | _BV(DDR_MOSI));
DDR_SPI &= ~_BV(DDR_MISO);
// Power up the SPI module
PRR &= ~_BV(PRSPI);
// Enable SPI and configure it as master
SPCR = 0x00;
SPCR |= (_BV(SPE) | _BV(MSTR));
// Set data order
switch(dataOrder)
{
case LSBFIRST:
SPCR |= _BV(DORD);
break;
case MSBFIRST:
SPCR &= ~_BV(DORD);
break;
}
// Set SPI mode
switch(mode)
{
case SPI_MODE0:
SPCR &= ~(_BV(CPOL) | _BV(CPHA));
break;
case SPI_MODE1:
SPCR |= _BV(CPHA);
SPCR &= ~_BV(CPOL);
break;
case SPI_MODE2:
SPCR &= ~_BV(CPHA);
SPCR |= _BV(CPOL);
break;
case SPI_MODE3:
SPCR |= (_BV(CPOL) | _BV(CPHA));
break;
}
// Set SPI clock frequency
switch(clkDiv)
{
case SCK_DIV2:
SPCR &= ~(_BV(SPR0) | _BV(SPR1));
SPSR |= _BV(SPI2X);
break;
case SCK_DIV4:
SPCR &= ~(_BV(SPR0) | _BV(SPR1));
SPSR &= ~_BV(SPI2X);
break;
case SCK_DIV8:
SPCR |= _BV(SPR0);
SPCR &= ~_BV(SPR1);
SPSR |= _BV(SPI2X);
break;
case SCK_DIV16:
SPCR |= _BV(SPR0);
SPCR &= ~_BV(SPR1);
SPSR &= ~_BV(SPI2X);
break;
case SCK_DIV32:
SPCR &= ~_BV(SPR0);
SPCR |= _BV(SPR1);
SPSR |= _BV(SPI2X);
break;
case SCK_DIV64:
SPCR |= _BV(SPR0);
SPCR |= _BV(SPR1);
SPSR |= _BV(SPI2X);
break;
case SCK_DIV128:
SPCR |= _BV(SPR0);
SPCR |= _BV(SPR1);
SPSR &= ~_BV(SPI2X);
break;
}
// SPI is now configured
configured = true;
return;
}
void spiModule::spiiocdeconf(void) {
// Clear SPI configuration, power down the SPI module and restore the values of DDR_SPI and PORT_SPI
SPCR = 0x00;
PRR |= _BV(PRSPI);
DDR_SPI = ddrOld;
PORT_SPI = portOld;
// SPI is no longer configured
configured = false;
return;
}
void spiModule::spiioctransmit(uint8_t txbyte, uint8_t * rxbyte) {
// Write TX byte to data register
SPDR = txbyte;
while(!(SPSR & _BV(SPIF)))
{
/* wait for data transmission to complete */
}
SPSR &= ~_BV(SPIF);
// Return RX byte by storing it at the specified location
if(rxbyte != NULL)
{
*rxbyte = SPDR;
}
return;
}
/* Ioctl handlers (verify that all arguments are appropriate and only then proceed with the ioctl) */
int spiModule::conf(int clkDiv, int dataOrder, int mode) {
// Return with error of SPI is not configured
if(!configured)
{
return -1;
}
// Verify validity of clkDiv (clock pulse division factor)
switch(clkDiv)
{
case SCK_DIV2:
break;
case SCK_DIV4:
break;
case SCK_DIV8:
break;
case SCK_DIV16:
break;
case SCK_DIV32:
break;
case SCK_DIV64:
break;
case SCK_DIV128:
break;
default:
return -1;
}
// Verify validity of dataOrder (order of byte transfer)
switch(dataOrder)
{
case LSBFIRST:
break;
case MSBFIRST:
break;
default:
return -1;
}
// Check validity of mode (SPI mode)
switch(mode)
{
case SPI_MODE0:
break;
case SPI_MODE1:
break;
case SPI_MODE2:
break;
case SPI_MODE3:
break;
default:
return -1;
}
// If all goes well, execute the ioctl
spiiocconf(clkDiv, dataOrder, mode);
return 0;
}
int spiModule::deconf(void) {
// If SPI is configured, deconfigure it
if(!configured)
{
return -1;
}
spiiocdeconf();
return 0;
}
int spiModule::transmit(uint8_t tx, uint8_t * rx) {
// If SPI is configured, make a byte exchange
if(!configured)
{
return -1;
}
spiioctransmit(tx, rx);
return 0;
}
// Public routines ///////////////////////////////////////
int spiModule::ioctl(int action, ... ) {
// This routine checks the value of action and executes the respective ioctl
// It returns with error if the value of action is not valid
va_list ap;
int clkDiv, dataOrder, mode;
uint8_t txbyte;
uint8_t * rxbyte;
int retVal;
switch(action)
{
case SPIIOCCONF:
va_start(ap, action);
clkDiv = va_arg(ap, int);
dataOrder = va_arg(ap, int);
mode = va_arg(ap, int);
va_end(ap);
retVal = conf(clkDiv, dataOrder, mode);
return retVal;
case SPIIOCDECONF:
retVal = deconf();
return retVal;
case SPIIOCTRANSMIT:
va_start(ap, action);
txbyte = va_arg(ap, uint8_t);
rxbyte = va_arg(ap, uint8_t*);
va_end(ap);
retVal = transmit(txbyte, rxbyte);
return retVal;
default:
return -1;
}
}
#endif
I'm compiling and uploading my code to the Arduino using the following commands (spiTest.cpp is a code that I used to test this library)
COMPILER=~/Softwares/arduino-1.6.8/hardware/tools/avr/bin/avr-g++
HEXGENERATOR=~/Softwares/arduino-1.6.8/hardware/tools/avr/bin/avr-objcopy
UPLOADER=~/Softwares/arduino-1.6.8/hardware/tools/avr/bin/avrdude
AVRDUDE_CFG=~/Softwares/arduino-1.6.8/hardware/tools/avr/etc/avrdude.conf
$COMPILER -c -g -w -D F_CPU=16000000UL -mmcu=atmega328p -std=gnu++11 -o spiTest.o spiTest.cpp
$COMPILER -mmcu=atmega328p spiTest.o -o spiTest
$HEXGENERATOR -O ihex -R .eeprom spiTest spiTest.hex
$UPLOADER -C $AVRDUDE_CFG -v -p atmega328p -c arduino -P /dev/ttyACM0 -b 115200 -D -U flash:w:spiTest.hex:i
I've used variadic functions to implement ioctl() before and it worked when I used the Arduino IDE to compile and upload my program. I don't understand what's preventing variadic functions from working properly in this code.

You are in the C++, you can do it in better. For example something like:
class SPIIOCONF_t {} SPIIOCONF;
class SPIIOCDECONF_t {} SPIIOCDECONF;
class SPIIOCTRANSMIT_t {} SPIIOCTRANSMIT;
int ioctl(SPIIOCONF_t, int clkDiv, int dataOrder, int mode) {
return conf(clkDiv, dataOrder, mode);
}
int ioctl(SPIIOCDECONF_t) {
return deconf();
}
int ioctl(SPIIOCTRANSMIT_t, uint8_t txbyte, uint8_t rxbyte) {
return transmit(txbyte, rxbyte);
}
void setup() {
Serial.begin(115200);
Serial.println(ioctl(SPIIOCONF, 10, 1, 1));
Serial.println(ioctl(SPIIOCDECONF));
uint8_t rx;
Serial.println(ioctl(SPIIOCTRANSMIT, 0xFF, &rx));
}
or similarly without defining dummy class instance, but you have to create one in the call:
class SPIIOCONF {};
class SPIIOCDECONF {};
class SPIIOCTRANSMIT {};
int ioctl(SPIIOCONF, int clkDiv, int dataOrder, int mode) {
return conf(clkDiv, dataOrder, mode);
}
int ioctl(SPIIOCDECONF) {
return deconf();
}
int ioctl(SPIIOCTRANSMIT, uint8_t txbyte, uint8_t rxbyte) {
return transmit(txbyte, rxbyte);
}
void setup() {
ioctl(SPIIOCONF{}, 10, 1, 1);
uint8_t rx;
Serial.println(ioctl(SPIIOCTRANSMIT{}, 0xFF, &rx));
ioctl(SPIIOCDECONF{});
}

Related

Arduino mega with L298n and Motors with Encoders not registering encoders

I am trying to follow a tutorial from youtube on using ROS with Arduino to control motors, and I have connected my L298N with the battery precisely as the video describes and have uploaded sketch 1 with the supporting folder and it loads properly. The Arduino is powered properly via USB, but that connection is not shown in the diagram. When I type the "e" command, I get the proper response of "0 0" and when I do the "o 255 255" it says "OK" and drives properly but upon using "e" to recheck the encoders I am getting the same "0 0". If anyone can spot something wrong with this, I would really appreciate the help in fixing it. Diagram and Code Below
Code:
#define USE_BASE // Enable the base controller code
//#undef USE_BASE // Disable the base controller code
/* Define the motor controller and encoder library you are using */
#ifdef USE_BASE
/* The Pololu VNH5019 dual motor driver shield */
//#define POLOLU_VNH5019
/* The Pololu MC33926 dual motor driver shield */
//#define POLOLU_MC33926
/* The RoboGaia encoder shield */
//#define ROBOGAIA
/* Encoders directly attached to Arduino board */
#define ARDUINO_ENC_COUNTER
/* L298 Motor driver*/
#define L298_MOTOR_DRIVER
#endif
//#define USE_SERVOS // Enable use of PWM servos as defined in servos.h
#undef USE_SERVOS // Disable use of PWM servos
/* Serial port baud rate */
#define BAUDRATE 57600
/* Maximum PWM signal */
#define MAX_PWM 255
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
/* Include definition of serial commands */
#include "commands.h"
/* Sensor functions */
#include "sensors.h"
/* Include servo support if required */
#ifdef USE_SERVOS
#include <Servo.h>
#include "servos.h"
#endif
#ifdef USE_BASE
/* Motor driver function definitions */
#include "motor_driver.h"
/* Encoder driver function definitions */
#include "encoder_driver.h"
/* PID parameters and functions */
#include "diff_controller.h"
/* Run the PID loop at 30 times per second */
#define PID_RATE 30 // Hz
/* Convert the rate into an interval */
const int PID_INTERVAL = 1000 / PID_RATE;
/* Track the next time we make a PID calculation */
unsigned long nextPID = PID_INTERVAL;
/* Stop the robot if it hasn't received a movement command
in this number of milliseconds */
#define AUTO_STOP_INTERVAL 2000
long lastMotorCommand = AUTO_STOP_INTERVAL;
#endif
/* Variable initialization */
// A pair of varibles to help parse serial commands (thanks Fergs)
int arg = 0;
int index = 0;
// Variable to hold an input character
char chr;
// Variable to hold the current single-character command
char cmd;
// Character arrays to hold the first and second arguments
char argv1[16];
char argv2[16];
// The arguments converted to integers
long arg1;
long arg2;
/* Clear the current command parameters */
void resetCommand() {
cmd = NULL;
memset(argv1, 0, sizeof(argv1));
memset(argv2, 0, sizeof(argv2));
arg1 = 0;
arg2 = 0;
arg = 0;
index = 0;
}
/* Run a command. Commands are defined in commands.h */
int runCommand() {
int i = 0;
char *p = argv1;
char *str;
int pid_args[4];
arg1 = atoi(argv1);
arg2 = atoi(argv2);
switch(cmd) {
case GET_BAUDRATE:
Serial.println(BAUDRATE);
break;
case ANALOG_READ:
Serial.println(analogRead(arg1));
break;
case DIGITAL_READ:
Serial.println(digitalRead(arg1));
break;
case ANALOG_WRITE:
analogWrite(arg1, arg2);
Serial.println("OK");
break;
case DIGITAL_WRITE:
if (arg2 == 0) digitalWrite(arg1, LOW);
else if (arg2 == 1) digitalWrite(arg1, HIGH);
Serial.println("OK");
break;
case PIN_MODE:
if (arg2 == 0) pinMode(arg1, INPUT);
else if (arg2 == 1) pinMode(arg1, OUTPUT);
Serial.println("OK");
break;
case PING:
Serial.println(Ping(arg1));
break;
#ifdef USE_SERVOS
case SERVO_WRITE:
servos[arg1].setTargetPosition(arg2);
Serial.println("OK");
break;
case SERVO_READ:
Serial.println(servos[arg1].getServo().read());
break;
#endif
#ifdef USE_BASE
case READ_ENCODERS:
Serial.print(readEncoder(LEFT));
Serial.print(" ");
Serial.println(readEncoder(RIGHT));
break;
case RESET_ENCODERS:
resetEncoders();
resetPID();
Serial.println("OK");
break;
case MOTOR_SPEEDS:
/* Reset the auto stop timer */
lastMotorCommand = millis();
if (arg1 == 0 && arg2 == 0) {
setMotorSpeeds(0, 0);
resetPID();
moving = 0;
}
else moving = 1;
leftPID.TargetTicksPerFrame = arg1;
rightPID.TargetTicksPerFrame = arg2;
Serial.println("OK");
break;
case MOTOR_RAW_PWM:
/* Reset the auto stop timer */
lastMotorCommand = millis();
resetPID();
moving = 0; // Sneaky way to temporarily disable the PID
setMotorSpeeds(arg1, arg2);
Serial.println("OK");
break;
case UPDATE_PID:
while ((str = strtok_r(p, ":", &p)) != '\0') {
pid_args[i] = atoi(str);
i++;
}
Kp = pid_args[0];
Kd = pid_args[1];
Ki = pid_args[2];
Ko = pid_args[3];
Serial.println("OK");
break;
#endif
default:
Serial.println("Invalid Command");
break;
}
}
/* Setup function--runs once at startup. */
void setup() {
Serial.begin(BAUDRATE);
// Initialize the motor controller if used */
#ifdef USE_BASE
#ifdef ARDUINO_ENC_COUNTER
//set as inputs
DDRD &= ~(1<<LEFT_ENC_PIN_A);
DDRD &= ~(1<<LEFT_ENC_PIN_B);
DDRC &= ~(1<<RIGHT_ENC_PIN_A);
DDRC &= ~(1<<RIGHT_ENC_PIN_B);
//enable pull up resistors
PORTD |= (1<<LEFT_ENC_PIN_A);
PORTD |= (1<<LEFT_ENC_PIN_B);
PORTC |= (1<<RIGHT_ENC_PIN_A);
PORTC |= (1<<RIGHT_ENC_PIN_B);
// tell pin change mask to listen to left encoder pins
PCMSK2 |= (1 << LEFT_ENC_PIN_A)|(1 << LEFT_ENC_PIN_B);
// tell pin change mask to listen to right encoder pins
PCMSK1 |= (1 << RIGHT_ENC_PIN_A)|(1 << RIGHT_ENC_PIN_B);
// enable PCINT1 and PCINT2 interrupt in the general interrupt mask
PCICR |= (1 << PCIE1) | (1 << PCIE2);
#endif
initMotorController();
resetPID();
#endif
/* Attach servos if used */
#ifdef USE_SERVOS
int i;
for (i = 0; i < N_SERVOS; i++) {
servos[i].initServo(
servoPins[i],
stepDelay[i],
servoInitPosition[i]);
}
#endif
}
/* Enter the main loop. Read and parse input from the serial port
and run any valid commands. Run a PID calculation at the target
interval and check for auto-stop conditions.
*/
void loop() {
while (Serial.available() > 0) {
// Read the next character
chr = Serial.read();
// Terminate a command with a CR
if (chr == 13) {
if (arg == 1) argv1[index] = NULL;
else if (arg == 2) argv2[index] = NULL;
runCommand();
resetCommand();
}
// Use spaces to delimit parts of the command
else if (chr == ' ') {
// Step through the arguments
if (arg == 0) arg = 1;
else if (arg == 1) {
argv1[index] = NULL;
arg = 2;
index = 0;
}
continue;
}
else {
if (arg == 0) {
// The first arg is the single-letter command
cmd = chr;
}
else if (arg == 1) {
// Subsequent arguments can be more than one character
argv1[index] = chr;
index++;
}
else if (arg == 2) {
argv2[index] = chr;
index++;
}
}
}
// If we are using base control, run a PID calculation at the appropriate intervals
#ifdef USE_BASE
if (millis() > nextPID) {
updatePID();
nextPID += PID_INTERVAL;
}
// Check to see if we have exceeded the auto-stop interval
if ((millis() - lastMotorCommand) > AUTO_STOP_INTERVAL) {;
setMotorSpeeds(0, 0);
moving = 0;
}
#endif
// Sweep servos
#ifdef USE_SERVOS
int i;
for (i = 0; i < N_SERVOS; i++) {
servos[i].doSweep();
}
#endif
}
Encoder Pin Designations:
/* *************************************************************
Encoder driver function definitions - by James Nugen
************************************************************ */
#ifdef ARDUINO_ENC_COUNTER
//below can be changed, but should be PORTD pins;
//otherwise additional changes in the code are required
#define LEFT_ENC_PIN_A PD2 //pin 2
#define LEFT_ENC_PIN_B PD3 //pin 3
//below can be changed, but should be PORTC pins
#define RIGHT_ENC_PIN_A PC4 //pin A4
#define RIGHT_ENC_PIN_B PC5 //pin A5
#endif
long readEncoder(int i);
void resetEncoder(int i);
void resetEncoders();
Encoder Driver:
/* *************************************************************
Encoder definitions
Add an "#ifdef" block to this file to include support for
a particular encoder board or library. Then add the appropriate
#define near the top of the main ROSArduinoBridge.ino file.
************************************************************ */
#ifdef USE_BASE
#ifdef ROBOGAIA
/* The Robogaia Mega Encoder shield */
#include "MegaEncoderCounter.h"
/* Create the encoder shield object */
MegaEncoderCounter encoders = MegaEncoderCounter(4); // Initializes the Mega Encoder Counter in the 4X Count mode
/* Wrap the encoder reading function */
long readEncoder(int i) {
if (i == LEFT) return encoders.YAxisGetCount();
else return encoders.XAxisGetCount();
}
/* Wrap the encoder reset function */
void resetEncoder(int i) {
if (i == LEFT) return encoders.YAxisReset();
else return encoders.XAxisReset();
}
#elif defined(ARDUINO_ENC_COUNTER)
volatile long left_enc_pos = 0L;
volatile long right_enc_pos = 0L;
static const int8_t ENC_STATES [] = {0,1,-1,0,-1,0,0,1,1,0,0,-1,0,-1,1,0}; //encoder lookup table
/* Interrupt routine for LEFT encoder, taking care of actual counting */
ISR (PCINT2_vect){
static uint8_t enc_last=0;
enc_last <<=2; //shift previous state two places
enc_last |= (PIND & (3 << 2)) >> 2; //read the current state into lowest 2 bits
left_enc_pos += ENC_STATES[(enc_last & 0x0f)];
}
/* Interrupt routine for RIGHT encoder, taking care of actual counting */
ISR (PCINT1_vect){
static uint8_t enc_last=0;
enc_last <<=2; //shift previous state two places
enc_last |= (PINC & (3 << 4)) >> 4; //read the current state into lowest 2 bits
right_enc_pos += ENC_STATES[(enc_last & 0x0f)];
}
/* Wrap the encoder reading function */
long readEncoder(int i) {
if (i == LEFT) return left_enc_pos;
else return right_enc_pos;
}
/* Wrap the encoder reset function */
void resetEncoder(int i) {
if (i == LEFT){
left_enc_pos=0L;
return;
} else {
right_enc_pos=0L;
return;
}
}
#else
#error A encoder driver must be selected!
#endif
/* Wrap the encoder reset function */
void resetEncoders() {
resetEncoder(LEFT);
resetEncoder(RIGHT);
}
#endif
I think if you use a Mega instead of an Uno, the pin ports are different.
So change the port from PD4 to PE4 and PD3 to PE5. Also, change PC4 to PF4 and PC5 to PF5.
In the Encoder.ino, you also have to change the ports accordingly.
Encoder.h:
#define LEFT_ENC_PIN_A PE4 //pin 2
#define LEFT_ENC_PIN_B PE5 //pin 3
//below can be changed, but should be PORTC pins
#define RIGHT_ENC_PIN_A PF5 //pin A4
#define RIGHT_ENC_PIN_B PF5 //pin A5
Encoder.ino:
/* Interrupt routine for LEFT encoder, taking care of actual counting */
ISR (PCINT2_vect){
static uint8_t enc_last=0;
enc_last <<=2; //shift previous state two places
enc_last |= (PINE & (3 << 2)) >> 2; //read the current state into lowest 2 bits
left_enc_pos += ENC_STATES[(enc_last & 0x0f)];
}
/* Interrupt routine for RIGHT encoder, taking care of actual counting */
ISR (PCINT1_vect){
static uint8_t enc_last=0;
enc_last <<=2; //shift previous state two places
enc_last |= (PINF & (3 << 4)) >> 4; //read the current state into lowest 2 bits
right_enc_pos += ENC_STATES[(enc_last & 0x0f)];
}

ISR not execute in rs484 with msp430fg6626 in receiving mode

Why code stucked in the ISR routine in msp430fg6626 microcontroller? here i performing the rs485 communiction with this uc and SN75176A max485 ic.during this i was set the buad rate at 9600 here data was successfully sent from uc and same received at the max485 ic but in receiving time data was not received at uc from max485 ic. why this occured i will share the code of same here please check and answer me.
i will share the samw code below
code was stuck in this line -> __bis_SR_register(LPM3_bits + GIE);
#include <msp430.h>
int ReceiveData;
int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // Stop WDT
CTSD16CCTL0 |= CTSD16SC; // Workaround for CTSD16OFFG errata
do
{
CTSD16CTL &= ~CTSD16OFFG;
}
while (CTSD16CTL&CTSD16OFFG); // End of CTSD16OFFG workaround
while(BAKCTL & LOCKBAK) // Unlock XT1 pins for operation
BAKCTL &= ~(LOCKBAK);
UCSCTL6 &= ~(XT1OFF); // XT1 On
UCSCTL6 |= XCAP_3; // Internal load cap
// Loop until XT1 fault flag is cleared
do
{
UCSCTL7 &= ~(XT2OFFG | XT1LFOFFG | DCOFFG);
// Clear XT2,XT1,DCO fault flags
SFRIFG1 &= ~OFIFG; // Clear fault flags
}while (SFRIFG1&OFIFG); // Test oscillator fault flag
//------------ Configuring MAX485 Control Lines ---------------//
P8SEL |= BIT4; // Assign P8.4 to ~RE DE and...
P8DIR |= BIT4; // P8.4 -> DE,-> ~RE output
P8OUT &= ~(BIT4); // ~RE & DE SET TO ZERO IN RECEIVING MODE
P8SEL |= 0x0C; // Assign P8.2 to UCA0TXD and...
P8DIR |= 0x0C; // P8.3 to UCA0RXD
UCA1CTL1 |= UCSWRST; // **Put state machine in reset**
UCA1CTL1 |= UCSSEL_1; // CLK = ACLK
UCA1BR0 = 0x03; // 32kHz/9600=3.41 (see User's Guide)
UCA1BR1 = 0x00; //
UCA1MCTL = UCBRS_3|UCBRF_0; // Modulation UCBRSx=3, UCBRFx=0
UCA1CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
UCA1IE |= UCRXIE; // Enable USCI_A1 RX interrupt
__bis_SR_register(LPM3_bits + GIE); // Enter LPM3, interrupts enabled***
__no_operation(); // For debugger
while(1)
{
while (!(UCA1IFG&UCTXIFG)); // USCI_A1 TX buffer ready?
// UCA1TXBUF = 0x55; // TX -> RXed character
// __delay_cycles (160000);
}
}
// Echo back RXed character, confirm TX buffer is ready first
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A1_VECTOR
__interrupt void USCI_A1_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_A1_VECTOR))) USCI_A1_ISR (void)
#else
#error Compiler not supported!
#endif
{
switch(__even_in_range(UCA1IV,4))
{
case 0:break; // Vector 0 - no interrupt
case 2: // Vector 2 - RXIFG
while (!(UCA1IFG&UCTXIFG)); // USCI_A1 TX buffer ready?
ReceiveData=UCA1RXBUF;
P8OUT |= BIT4; // ~RE & DE SET TO HIGH FOR TRANSMITTING MODE
__delay_cycles (16000);
UCA1TXBUF = ReceiveData; // TX -> RXed character
__delay_cycles (16000);
P8OUT |= ~(BIT4); // ~RE & DE SET TO ZERO IN RECEIVING MODE
__delay_cycles (16000);
break;
case 4:break; // Vector 4 - TXIFG
default: break;
}
}

How to publish and subscribe to MQTT broker through GSM Module in Arduino/ESP8266?

I am currently working in a project where I have to publish and possibly subscribe to MQTT topic over GSM network (I am using ESP8266 and Ai Thinker A6 GSM Module). So far I am able to publish message to the broker once using MQTT Example code from TinyGSM library,where they pass the GPRS client instance to Pubsub Client class, but when I add a code in loop to publish message continuously every n seconds. The message is published only once or twice and then freezes.
I doubt the mqttclient.loop() function in the void loop(). But, I am just wondering is there any other library which is completely tested, because the TinyGSM developer itself has mentioned this code is not tested in github.
The example code with mqtt publish in loop
// Select your modem:
#define TINY_GSM_MODEM_SIM800
// #define TINY_GSM_MODEM_SIM808
// #define TINY_GSM_MODEM_SIM868
// #define TINY_GSM_MODEM_SIM900
// #define TINY_GSM_MODEM_SIM7000
// #define TINY_GSM_MODEM_SIM5360
// #define TINY_GSM_MODEM_SIM7600
// #define TINY_GSM_MODEM_UBLOX
// #define TINY_GSM_MODEM_SARAR4
// #define TINY_GSM_MODEM_M95
// #define TINY_GSM_MODEM_BG96
// #define TINY_GSM_MODEM_A6
// #define TINY_GSM_MODEM_A7
// #define TINY_GSM_MODEM_M590
// #define TINY_GSM_MODEM_MC60
// #define TINY_GSM_MODEM_MC60E
// #define TINY_GSM_MODEM_ESP8266
// #define TINY_GSM_MODEM_XBEE
// #define TINY_GSM_MODEM_SEQUANS_MONARCH
// Set serial for debug console (to the Serial Monitor, default speed 115200)
#define SerialMon Serial
// Set serial for AT commands (to the module)
// Use Hardware Serial on Mega, Leonardo, Micro
#define SerialAT Serial1
// or Software Serial on Uno, Nano
//#include <SoftwareSerial.h>
//SoftwareSerial SerialAT(2, 3); // RX, TX
// See all AT commands, if wanted
// #define DUMP_AT_COMMANDS
// Define the serial console for debug prints, if needed
#define TINY_GSM_DEBUG SerialMon
// Range to attempt to autobaud
#define GSM_AUTOBAUD_MIN 9600
#define GSM_AUTOBAUD_MAX 115200
// Add a reception delay - may be needed for a fast processor at a slow baud rate
// #define TINY_GSM_YIELD() { delay(2); }
// Define how you're planning to connect to the internet
#define TINY_GSM_USE_GPRS true
#define TINY_GSM_USE_WIFI false
// set GSM PIN, if any
#define GSM_PIN ""
// Your GPRS credentials, if any
const char apn[] = "YourAPN";
const char gprsUser[] = "";
const char gprsPass[] = "";
// Your WiFi connection credentials, if applicable
const char wifiSSID[] = "YourSSID";
const char wifiPass[] = "YourWiFiPass";
// MQTT details
const char* broker = "broker.hivemq.com";
const char* topicLed = "GsmClientTest/led";
const char* topicInit = "GsmClientTest/init";
const char* topicLedStatus = "GsmClientTest/ledStatus";
#include <TinyGsmClient.h>
#include <PubSubClient.h>
// Just in case someone defined the wrong thing..
#if TINY_GSM_USE_GPRS && not defined TINY_GSM_MODEM_HAS_GPRS
#undef TINY_GSM_USE_GPRS
#undef TINY_GSM_USE_WIFI
#define TINY_GSM_USE_GPRS false
#define TINY_GSM_USE_WIFI true
#endif
#if TINY_GSM_USE_WIFI && not defined TINY_GSM_MODEM_HAS_WIFI
#undef TINY_GSM_USE_GPRS
#undef TINY_GSM_USE_WIFI
#define TINY_GSM_USE_GPRS true
#define TINY_GSM_USE_WIFI false
#endif
#ifdef DUMP_AT_COMMANDS
#include <StreamDebugger.h>
StreamDebugger debugger(SerialAT, SerialMon);
TinyGsm modem(debugger);
#else
TinyGsm modem(SerialAT);
#endif
TinyGsmClient client(modem);
PubSubClient mqtt(client);
#define LED_PIN 13
int ledStatus = LOW;
uint32_t lastReconnectAttempt = 0;
void mqttCallback(char* topic, byte* payload, unsigned int len) {
SerialMon.print("Message arrived [");
SerialMon.print(topic);
SerialMon.print("]: ");
SerialMon.write(payload, len);
SerialMon.println();
// Only proceed if incoming message's topic matches
if (String(topic) == topicLed) {
ledStatus = !ledStatus;
digitalWrite(LED_PIN, ledStatus);
mqtt.publish(topicLedStatus, ledStatus ? "1" : "0");
}
}
boolean mqttConnect() {
SerialMon.print("Connecting to ");
SerialMon.print(broker);
// Connect to MQTT Broker
boolean status = mqtt.connect("GsmClientTest");
// Or, if you want to authenticate MQTT:
//boolean status = mqtt.connect("GsmClientName", "mqtt_user", "mqtt_pass");
if (status == false) {
SerialMon.println(" fail");
return false;
}
SerialMon.println(" success");
mqtt.publish(topicInit, "GsmClientTest started");
mqtt.subscribe(topicLed);
return mqtt.connected();
}
void setup() {
// Set console baud rate
SerialMon.begin(115200);
delay(10);
pinMode(LED_PIN, OUTPUT);
// !!!!!!!!!!!
// Set your reset, enable, power pins here
// !!!!!!!!!!!
SerialMon.println("Wait...");
// Set GSM module baud rate
// TinyGsmAutoBaud(SerialAT,GSM_AUTOBAUD_MIN,GSM_AUTOBAUD_MAX);
SerialAT.begin(9600);
delay(3000);
// Restart takes quite some time
// To skip it, call init() instead of restart()
SerialMon.println("Initializing modem...");
modem.restart();
// modem.init();
String modemInfo = modem.getModemInfo();
SerialMon.print("Modem Info: ");
SerialMon.println(modemInfo);
#if TINY_GSM_USE_GPRS
// Unlock your SIM card with a PIN if needed
if ( GSM_PIN && modem.getSimStatus() != 3 ) {
modem.simUnlock(GSM_PIN);
}
#endif
#if TINY_GSM_USE_WIFI
// Wifi connection parameters must be set before waiting for the network
SerialMon.print(F("Setting SSID/password..."));
if (!modem.networkConnect(wifiSSID, wifiPass)) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" success");
#endif
#if TINY_GSM_USE_GPRS && defined TINY_GSM_MODEM_XBEE
// The XBee must run the gprsConnect function BEFORE waiting for network!
modem.gprsConnect(apn, gprsUser, gprsPass);
#endif
SerialMon.print("Waiting for network...");
if (!modem.waitForNetwork()) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" success");
if (modem.isNetworkConnected()) {
SerialMon.println("Network connected");
}
#if TINY_GSM_USE_GPRS
// GPRS connection parameters are usually set after network registration
SerialMon.print(F("Connecting to "));
SerialMon.print(apn);
if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" success");
if (modem.isGprsConnected()) {
SerialMon.println("GPRS connected");
}
#endif
// MQTT Broker setup
mqtt.setServer(broker, 1883);
mqtt.setCallback(mqttCallback);
}
void loop() {
if (!mqtt.connected()) {
SerialMon.println("=== MQTT NOT CONNECTED ===");
// Reconnect every 10 seconds
uint32_t t = millis();
if (t - lastReconnectAttempt > 10000L) {
lastReconnectAttempt = t;
if (mqttConnect()) {
lastReconnectAttempt = 0;
}
}
delay(100);
return;
}
else
{
mqtt.publish("Topic/test","Hi");
delay(1000);
}
mqtt.loop();
}

SPI Problem Arduino Mega with pressure sensor MS5803-05BA

I need your help for a project.
I have actually 2 parallel sensors of the type: MS5803-05BA, which supports I2C and SPI connection. One sensor is on I2C bus and one sensor is on SPI. They are both sending to my Arduino Mega. The I2C works perfect with short cables.
Here the datasheet of the sensor:
https://www.amsys.de/downloads/data/MS5803-05BA-AMSYS-datasheet.pdf
For some informations who wants to do the same with I2C. Here you can find a good code. (You can find the other MS580X typs there too). For the communication between the sensor and the Arduino Mega you need an logic converter like this txs0108e, which can be bought with a break out board (you need pull up resistors on the sensor side!):
https://github.com/millerlp/MS5803_05
But to my problem: I have an sensor distance for about 3-5 meters and the I2C connections doesnt work. Yes I can try to fix the pullup resistors but it doesnt worked for me (I have tried some different lower resistors between 3-10kOhm). Therefore I want to switch to the SPI bus.
I have edit the code from https://github.com/millerlp/MS5803_05, https://github.com/vic320/Arduino-MS5803-14BA and https://arduino.stackexchange.com/questions/13720/teensy-spi-and-pressure-sensor.
The File is added. (You have to put the .h and .cpp files in the folder of the arduino code (.spi).
I have problems with the code from the SPI (ccp and header). There is no right communication. I have checked my cables twice. I couldnt find a problem and the connection with the txs0108e works for parallel I2C sensor. Both sensors are working on I2C.
Here is the main code (arduino .spi) for SPI and I2C parallel:
/_____ I N C L U D E S
#include <stdio.h>
#include <math.h>
#include <SPI.h>
#include <Wire.h>
#include "MS5803_05.h"
#include "MS5803_05_SPI.h"
const int miso_port = 50; //SDI
const int mosi_port = 51; //SDO
const int sck_port = 52; //SLCK
const int slaveSelectPin = 53; // CSB
MS_5803 sensor = MS_5803(512);
MS_5803_SPI sensor_spi = MS_5803_SPI(4096, slaveSelectPin);
void setup()
{
pinMode(miso_port, INPUT);
pinMode(mosi_port, OUTPUT);
pinMode(slaveSelectPin, OUTPUT);
pinMode(sck_port, OUTPUT);
Serial.begin(9600);
//SPI BUS
if (sensor_spi.initializeMS_5803_SPI()) {
Serial.println( "MS5803 SPI CRC check OK." );
}
else {
Serial.println( "MS5803 SPI CRC check FAILED!" );
}
//I2C BUS
delay(1000);
if (sensor.initializeMS_5803()) {
Serial.println( "MS5803 I2C CRC check OK." );
}
else {
Serial.println( "MS5803 I2C CRC check FAILED!" );
}
}
void loop()
{
Serial.println("SPI Sensor first pressure [mbar], than temperature[°C]:");
sensor_spi.readSensor();
// Show pressure
Serial.print("Pressure = ");
Serial.print(sensor_spi.pressure());
Serial.println(" mbar");
// Show temperature
Serial.print("Temperature = ");
Serial.print(sensor_spi.temperature());
Serial.println("C");
////********************************************************
Serial.println("");
Serial.println("I2C Sensor first pressure [mbar], than temperature[°C]:");
sensor.readSensor();
// Show pressure
Serial.print("Pressure = ");
Serial.print(sensor.pressure());
Serial.println(" mbar");
// Show temperature
Serial.print("Temperature = ");
Serial.print(sensor.temperature());
Serial.println("C");
delay(2000);
}
}
The first connection with SPI is here (.cpp):
#include "MS5803_05_SPI.h"
#include <SPI.h>
#define CMD_RESET 0x1E // ADC reset command
#define CMD_ADC_READ 0x00 // ADC read command
#define CMD_ADC_CONV 0x40 // ADC conversion command
#define CMD_ADC_D1 0x00 // ADC D1 conversion
#define CMD_ADC_D2 0x10 // ADC D2 conversion
#define CMD_ADC_256 0x00 // ADC resolution=256
#define CMD_ADC_512 0x02 // ADC resolution=512
#define CMD_ADC_1024 0x04 // ADC resolution=1024
#define CMD_ADC_2048 0x06 // ADC resolution=2048
#define CMD_ADC_4096 0x08 // ADC resolution=4096
#define CMD_PROM_RD 0xA0 // Prom read command
#define spi_write SPI_MODE3
#define spi_write2 SPI_MODE1
// Create array to hold the 8 sensor calibration coefficients
static unsigned int sensorCoeffs[8]; // unsigned 16-bit integer (0-65535)
// D1 and D2 need to be unsigned 32-bit integers (long 0-4294967295)
static uint32_t D1 = 0; // Store uncompensated pressure value
static uint32_t D2 = 0; // Store uncompensated temperature value
// These three variables are used for the conversion steps
// They should be signed 32-bit integer initially
// i.e. signed long from -2147483648 to 2147483647
static int32_t dT = 0;
static int32_t TEMP = 0;
// These values need to be signed 64 bit integers
// (long long = int64_t)
static int64_t Offset = 0;
static int64_t Sensitivity = 0;
static int64_t T2 = 0;
static int64_t OFF2 = 0;
static int64_t Sens2 = 0;
// Some constants used in calculations below
const uint64_t POW_2_33 = 8589934592ULL; // 2^33 = 8589934592
SPISettings settings_write(500000, MSBFIRST, spi_write);
SPISettings settings_write2(500000, MSBFIRST, spi_write2);
//-------------------------------------------------
// Constructor
MS_5803_SPI::MS_5803_SPI( uint16_t Resolution, uint16_t cs) {
// The argument is the oversampling resolution, which may have values
// of 256, 512, 1024, 2048, or 4096.
_Resolution = Resolution;
//Chip Select
_cs=cs;
}
boolean MS_5803_SPI::initializeMS_5803_SPI(boolean Verbose) {
digitalWrite( _cs, HIGH );
SPI.begin();
// Reset the sensor during startup
resetSensor();
if (Verbose)
{
// Display the oversampling resolution or an error message
if (_Resolution == 256 | _Resolution == 512 | _Resolution == 1024 | _Resolution == 2048 | _Resolution == 4096){
Serial.print("Oversampling setting: ");
Serial.println(_Resolution);
} else {
Serial.println("*******************************************");
Serial.println("Error: specify a valid oversampling value");
Serial.println("Choices are 256, 512, 1024, 2048, or 4096");
Serial.println("*******************************************");
}
}
// Read sensor coefficients
for (int i = 0; i < 8; i++ )
{
SPI.beginTransaction(settings_write2);
digitalWrite(_cs, LOW); //csb_lo(); // pull CSB low
unsigned int ret;
unsigned int rC = 0;
SPI.transfer(CMD_PROM_RD + i * 2); // send PROM READ command
/*
ret = SPI.transfer(0x00); // send 0 to read the MSB
rC = 256 * ret;
ret = SPI.transfer(0x00); // send 0 to read the LSB
rC = rC + ret;
*/
// send a value of 0 to read the first byte returned:
rC = SPI.transfer( 0x00 );
rC = rC << 8;
rC |= SPI.transfer( 0x00 ); // and the second byte
sensorCoeffs[i] = (rC);
digitalWrite( _cs, HIGH );
delay(3);
}
//SPI.endTransaction(); // interrupt can now be accepted
// The last 4 bits of the 7th coefficient form a CRC error checking code.
unsigned char p_crc = sensorCoeffs[7];
// Use a function to calculate the CRC value
unsigned char n_crc = MS_5803_CRC(sensorCoeffs);
if (Verbose) {
for (int i = 0; i < 8; i++ )
{
// Print out coefficients
Serial.print("C");
Serial.print(i);
Serial.print(" = ");
Serial.println(sensorCoeffs[i]);
delay(10);
}
Serial.print("p_crc: ");
Serial.println(p_crc);
Serial.print("n_crc: ");
Serial.println(n_crc);
}
// If the CRC value doesn't match the sensor's CRC value, then the
// connection can't be trusted. Check your wiring.
if (p_crc != n_crc) {
return false;
}
// Otherwise, return true when everything checks out OK.
return true;
}
// Sends a power on reset command to the sensor.
void MS_5803_SPI::resetSensor() {
SPI.beginTransaction(settings_write);
digitalWrite(_cs, LOW); //csb_lo(); // pull CSB low to start the command
SPI.transfer(CMD_RESET); // send reset sequence
delay(3); // wait for the reset sequence timing delay(3)
digitalWrite(_cs, HIGH); //csb_hi(); // pull CSB high to finish the command
SPI.endTransaction(); // interrupt can now be accepted
}
The Code can be downloaded at: https://forum.arduino.cc/index.php?topic=670661.0
There you can find the schematic and output picture too.
Thanks a lot :).

ERROR SPI on ATmega328P of Arduino

I use SPI on ATmega328 with raw code, data is transferred correctly, but the value return just correct in the second time. I don't know why. I think the data buffer register doesn't update immediately, when I push the button (this is video left is yellow LED, right is red LED: https://drive.google.com/open?id=1bf2XlxRBGCaUo0j2ezB2XFxfSItUmChN and code below)
I use Arduino Uno is a master to send data and get response. Arduino Nano is a slave to receive data and response to master.
Arduino Uno (master) code:
#define DDR_SPI DDRB
#define PORT_SPI PORTB
#define MOSI 3
#define SCK 5
#define SS 2
#define red 2
#define cbi(port, bits) (port) &= ~(1 << (bits))
#define sbi(port, bits) (port) |= (1 << (bits))
volatile uint8_t Data1;
volatile uint8_t Data2;
void setup()
{
Serial.begin(9600); //debug by UART
SPCR = 0; // Reset SPCR = 0
DDR_SPI |= (1<<MOSI)|(1<<SCK)|(1<<SS);// MOSI,SCK,SS - OUTPUT , MISO - INPUT
SPCR |= (1<<SPE)|(1<<MSTR)|(1<<SPR0); // Enable spi , Set master , div/16
pinMode(red,OUTPUT); // led output at pin 2
pinMode(6,INPUT_PULLUP); // internal res input at pin6
pinMode(7,INPUT_PULLUP); // internal res input at pin7
sbi(PORT_SPI,SS); // disable slave
}
uint8_t SPI_MasterTransmit(uint8_t cData)
{
SPDR = cData; // Start transmission
delay(50);
while(bit_is_clear(SPSR,SPIF)); //Wait for transmission complete
return SPDR;
}
void loop()
{
if(bit_is_clear(PIND,6)) // if i push button at pin 6
{
while(bit_is_clear(PIND,6)); // if i still push button at pin 6
cbi(PORTB,SS); // enable slave
Data1 = SPI_MasterTransmit(1); // send value 1 to slave
Serial.print(Data1); // debug
delay(50);
if(Data1 == 2) //if slave response value = 2
digitalWrite(red,LOW); //turnOFF led at pin 2
sbi(PORT_SPI,SS); // disable slave
}
else if(bit_is_clear(PIND,7)) // if i push button at pin 7
{
while(bit_is_clear(PIND,7)); // if i still push button at pin 7
cbi(PORT_SPI,SS); // disable slave
Data2 = SPI_MasterTransmit(3); // send value 3 to slave
Serial.print(Data2); // debug
delay(50);
if(Data2==4) //if slave response value = 4
digitalWrite(red,HIGH); //turnON led at pin 2
sbi(PORT_SPI,SS); // disable slave
}
}
Arduino Nano (slave) code:
#define MISO 4
#define yellow 2
#define cbi(port, bits) (port) &= ~(1 << (bits))
#define sbi(port, bits) (port) |= (1 << (bits))
volatile uint8_t Data;
void setup()
{
SPCR = 0; // reset SPCR = 0
DDRB |= (1<<MISO); // MISO - OUTPUT , SCK,MOSI,SS - INPUT
SPCR |= (1<<SPE)|(1<<SPIE); // enable spi , spi_interrupt
pinMode(yellow ,OUTPUT); // Led output at pin2
}
void SPI_Response(uint8_t cData)
{
SPDR = cData; //Start transmission
while(bit_is_clear(SPSR,SPIF)); //Wait for transmission complete
}
void loop()
{
}
ISR(SPI_STC_vect) // Vector interrupt spi
{
Data = SPDR; // volatile Data = data receive
if(Data == 1)
{
digitalWrite(yellow ,HIGH); // i turnOn led if i receive data = 5
SPI_Response(2); // and response to master a value = 7
delay(10);
}
else if(Data == 3)
{
digitalWrite(yellow,LOW); // i turnOFF led if i receive data = 6
SPI_Response(4); //and response to master a value = 8
delay(10);
}
}
You know the four wire SPI is full duplex, right? The master and the slave are sending the data simultaneously.
The common way how to do what you want is sending control byte and then dummy byte (or bytes) to receive the data.

Resources