Problem interfacing ATmega328(master) with ATtiny85(slave) through SPI

Hello,
I am working on light dimmer project. I am using ATtiny85 for generating firing pulses required for voltage control and this ATtiny85 receives the required output voltage value from ATmega328 to perform voltage control function (in the form of firing angle delay in milliseconds). To perform this, I have planned to use pin change interrupt for voltage control purpose, and SPI -Three wire mode of USI- for communicating with ATmega328 in ATtiny85.

The ATmega328 -configured as master- transmits the time delay value to ATtiny85. This is where I am stuck. I am not able to enable them communicate with each other properly. I think I am having synchronizing problem. Kindly help me out with this. I am attaching the master and slave codes.

ATtiny85 (slave) Code

#define DO 1 //IC PIN 6
#define DI 0 //IC PIN 5
#define SCK 2 //IC PIN 7
#define opto_triac 4 //IC PIN 3
int ZCD = 3; //IC PIN 2, Pin Change Interrupt, Zero Crossing Detector
volatile int alpha = 0;

void setup() {
  pinMode(DO, OUTPUT);             //Configuring pins for Three Wire Mode
  pinMode(DI, INPUT_PULLUP);
  pinMode(SCK, INPUT_PULLUP);
  pinMode(ZCD, INPUT_PULLUP);
  pinMode(opto_triac, OUTPUT);

  SREG |= 0b10000000;     //Global Interrupt Enable
  GIMSK |= 0b00100000;    //Pin Change Interrupt Enable
  PCMSK |= 0b1 << ZCD;    //Enable ZCD pin for PCINT

  USICR |= 0b01011000;    //Initialize SPI
  USIDR = 8;       //Load dummy data to USI Data Register
}

ISR (PCINT0_vect) {   //Performs firing functions required for voltage control
  delayMicroseconds(alpha * 1000);
  digitalWrite(opto_triac, 1);
  delayMicroseconds(50);
  digitalWrite(opto_triac, 0);
}


ISR (USI_OVF_vect) {
  alpha = USIDR;
  USISR |= 0b01000000; //Clears Overflow Interrupt flag
}
void loop() {
}

ATmega328 (Master) code for testing purpose:

#include <SPI.h>


void setup() {
  pinMode(slaveSelectPin, OUTPUT);
  SPI.begin();
  Serial.begin(9600);
}

void loop() {
  digitalPotWrite(5);
  delay(3000);
  digitalPotWrite(6);
  delay(3000);
  digitalPotWrite(7);
  delay(3000);
  digitalPotWrite(8);
  delay(3000);
}

void digitalPotWrite(int a) {
  int a1=SPI.transfer(a);
  Serial.println(a1);
}

If I give a constant value for “alpha” then the dimmer circuit works well, but if I vary “alpha” using SPI then the lamp flickers for every 3seconds because for every 3 seconds SPI transmits data. But the brightness is the same even though the value of “alpha” should have been changed by now due to SPI transfer.

Also when I see the value received by the ATmega328 (master) through serial monitor, I am getting 0 continuously for every 3 seconds when transfer takes place. So I think I am having a synchronization problem here.

I am just a beginner, kindly forgive me if I am doing a very stupid mistake and kindly help me out.
Thank you.

I don't know about ATtiny, and don't understand your SPI implementation. Are you sure that OVF is the right flag/interrupt for a received byte?

I'd not use delayMicroseconds in an ISR, with a delay of up to 1/2 (50/60Hz mains?) cycle. This may corrupt the SPI transmission of multiple bytes.

Your biggest mistake is sending an int (2 bytes) while receiving only 1 byte in the ISR. This makes alpha either the low or high byte of the int, depending on the transmission order. This change may fix the flicker:

void digitalPotWrite(byte a) {

Thanks a lot. I will look into it. And regarding delayMicroseconds in PCINT0 ISR, are you saying that bits may be sent by master while slave is waiting in the delay portion? Am I correctly understanding what you are saying? I thought bit transfer will be happening concurrently like another thread. Is it wrong? My basics are very weak since i did not see the architectures of the MCUs.

The overflow flag is set when transfer is complete, and since overflow interrupt is enabled in USICR, interrupt will be triggered when transfer is complete so that i can read the data.

A single-core (8 bit) Arduino has nothing like parallel threads. On entry of an ISR all other interrupts are disabled automatically, so that no other ISR can execute until the current ISR exits. Enabling interrupts inside an ISR is possible, but then a delayMicroseconds() inside the interrupted ISR cannot work properly.

The SPI transfers are handled by parallel hardware, but if an incoming byte is not saved before the transmission of the next byte, it will be lost. Unless an ATtiny has additional SPI data buffer registers (dunno).

I'd suggest to use an timer for the dimmer signal generation. When the zero-crossing interrupt only has to start the timer, blocking interrupts only for very short time, the SPI transfers and other activities can be handled in loop() or within their own ISR.

Thanks a ton. This helps me get an idea about how the timing diagram would be and especially that "integer-byte" thing, really thank you so much.