Versão 1:
Estou usando um Raspberry Pi Pico como mestre SPI e um ATtiny841 como escravo SPI.
Código mestre:
#include "pico/stdlib.h"
#include "hardware/spi.h"
#include <stdio.h>
#define SPI_PORT spi0
#define PIN_MISO 16
#define PIN_MOSI 19
#define PIN_SCK 18
#define PIN_CS 17
uint8_t tx_dummy = 0xAA;
uint8_t rx_buf[3];
void spi_init_master()
{
spi_init(SPI_PORT, 1000000);
gpio_set_function(PIN_MISO, GPIO_FUNC_SPI);
gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI);
gpio_set_function(PIN_SCK, GPIO_FUNC_SPI);
gpio_init(PIN_CS);
gpio_set_dir(PIN_CS, GPIO_OUT);
gpio_put(PIN_CS, 1);
}
int main()
{
stdio_init_all();
spi_init_master();
while(true)
{
gpio_put(PIN_CS, 0); // Select slave
tx_dummy = 0xAA;
for(int i = 0; i < 3; i++)
{
spi_write_read_blocking(SPI_PORT, &tx_dummy, &rx_buf[i], 1);
tx_dummy++;
}
gpio_put(PIN_CS, 1); // Deselect slave
printf("Ontvangen bytes: ");
for(int i = 0; i < 3; i++)
{
printf("0x%02X ", rx_buf[i]);
}
printf("\n");
sleep_ms(1000);
}
}
Código escravo:
#define SS PA7
#define MOSI PA6
#define MISO PA5
#define SCK PA4
byte dataToSend[3] = {0xDE, 0xAD, 0xBE};
volatile byte sendIndex = 0;
void setup() {
pinMode(SCK, INPUT);
pinMode(MOSI, INPUT);
pinMode(MISO, OUTPUT);
pinMode(SS, INPUT);
SPCR = (1 << SPE) | (1 << SPIE);
SPDR = dataToSend[0];
}
ISR(SPI_STC_vect) {
byte received = SPDR;
sendIndex++;
if (sendIndex >= 3) {
sendIndex = 0;
}
SPDR = dataToSend[sendIndex];
}
void loop() {
}
Em vez de receber o array {0xDE, 0xAD, 0xBE}, recebo {0xDE, 0xAA, 0xAB}.
Alguém sabe como posso escrever o código para que o registrador SPDR do ATtiny841 sobrescreva o valor fictício do mestre com o próximo valor do array antes que o mestre peça um novo valor?
Já tentei com uma interrupção, já tentei sem interrupção. Mas sempre recebo os valores fictícios do mestre como entrada. Eu preferiria que funcionasse com uma interrupção.
Versão 2:
Gerando uma interrupção no pino CS do ATtiny841 e colocando alguns pequenos atrasos no código mestre do Pico, consegui transferir dados do escravo ATiny841 para o mestre Pi Pico.
(Usar a interrupção SPI sempre retorna os dados fictícios que envio do mestre para o escravo)
Agora, tento adicionar uma estrutura de registrador enviando 2 bytes (byte 1 = endereço do registrador, byte 2 = valor fictício). A cada byte, o CS vai para os níveis BAIXO e ALTO para acionar a interrupção no escravo.
Este código quase funciona, mas se o mestre solicitar o registro 0x01, ele receberá o valor do registro 0x02. Se o mestre solicitar o registro 0x02, ele receberá o valor do registro 0x01.
Alguém viu/sabe como posso consertar isso?
Saída do mestre:
Reg value 0x01: 0x99 - 0x01
Reg value 0x02: 0x43 - 0x02
Reg value 0x01: 0x99 - 0x01
Reg value 0x02: 0x43 - 0x02
Reg value 0x01: 0x99 - 0x01
Reg value 0x02: 0x43 - 0x02
Código mestre:
#include "pico/stdlib.h"
#include "hardware/spi.h"
#include <stdio.h>
#define SPI_PORT spi0
#define PIN_MISO 16
#define PIN_MOSI 19
#define PIN_SCK 18
#define PIN_CS 17
uint8_t tx_dummy = 0xAA;
uint8_t rx_buf[2];
void spi_init_master()
{
spi_init(SPI_PORT, 1000000);
gpio_set_function(PIN_MISO, GPIO_FUNC_SPI);
gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI);
gpio_set_function(PIN_SCK, GPIO_FUNC_SPI);
gpio_init(PIN_CS);
gpio_set_dir(PIN_CS, GPIO_OUT);
gpio_put(PIN_CS, 1);
}
int main()
{
stdio_init_all();
spi_init_master();
uint8_t adress = 0x01;
uint8_t test = 0x02;
while(true)
{
gpio_put(PIN_CS, 0);
sleep_us(10);
spi_write_read_blocking(SPI_PORT, &adress, &rx_buf[0], 1);
gpio_put(PIN_CS, 1);
sleep_us(10);
gpio_put(PIN_CS, 0);
sleep_us(10);
spi_write_read_blocking(SPI_PORT, 0x00, &rx_buf[1], 1);
gpio_put(PIN_CS, 1);
sleep_us(10);
printf("Reg value 0x01: 0x%02X - 0x%02X\n", rx_buf[0], rx_buf[1]);
sleep_ms(1000);
gpio_put(PIN_CS, 0);
sleep_us(10);
spi_write_read_blocking(SPI_PORT, &test, &rx_buf[0], 1);
gpio_put(PIN_CS, 1);
sleep_us(10);
gpio_put(PIN_CS, 0);
sleep_us(10);
spi_write_read_blocking(SPI_PORT, 0x00, &rx_buf[1], 1);
gpio_put(PIN_CS, 1);
sleep_us(10);
printf("Reg value 0x02: 0x%02X - 0x%02X\n", rx_buf[0], rx_buf[1]);
sleep_ms(1000);
}
}
Código escravo:
#define SS PA7
#define MOSI PA6
#define MISO PA5
#define SCK PA4
volatile byte registerMap[3] = {};
volatile bool lastSSState = 0;
volatile byte receivedAddress = 0;
volatile byte transactionStep = 0;
void setup()
{
pinMode(SCK, INPUT);
pinMode(MOSI, INPUT);
pinMode(MISO, OUTPUT);
pinMode(SS, INPUT);
SPCR = (1 << SPE);
SPDR = registerMap[0];
registerMap[0x01] = 0x43;
registerMap[0x02] = 0x99;
PCMSK0 |= (1 << PCINT7);
GIMSK |= (1 << PCIE0);
lastSSState = digitalRead(SS);
sei();
}
void loop(){}
ISR(PCINT0_vect)
{
bool currentState = digitalRead(SS);
if(lastSSState && !currentState) //Falling edge
{
if(transactionStep == 0) //First falling edge
{
while(!(SPSR & (1 << SPIF)));
byte received = SPDR;
receivedAddress = received;
if(SPSR & (1 << WCOL))
{
volatile byte tmp = SPDR;
}
SPDR = registerMap[receivedAddress];
transactionStep = 1;
}
else if(transactionStep == 1) //Second falling edge
{
while(!(SPSR & (1 << SPIF)));
volatile byte dummy = SPDR;
transactionStep = 0;
receivedAddress = 0;
if(SPSR & (1 << WCOL))
{
volatile byte tmp = SPDR;
}
SPDR = 0x00;
}
}
lastSSState = currentState;
}