Per necessità legate alle tempistiche particolarmente stringenti ho la necessità di implementare una parte del programma in assembly per ATMEGA 238P. Ho consultato vari esempi, ho scaricato un testo "Inline Assembler Cookbook" che mi ha chiarito molti dubbi. Ho scritto il programma regolarmente compilato, ma quando effettuo la verifica funzionale mi accorgo che commette un errore, in particolare l'operazione di mascheratura non funziona correttamente e solo il MSB viene riconosciuto, tutti gli altri vengono rappresentati con uno 0.
Altra informazione: eseiste un modo più elegante e compatto per scrivere lo stesso codice?
Grazie per le vostre risposte e fatemi sapere se, essendo il primo post, ho commesso delle scorrettezze. Buona giornata
Questo è il programma:
#define DATA_IN 4 // Pin IN del chip WS8212B
#define NUM_LED 36
#define numvals 3
uint8_t pixels[12]= {0xFF,0xFF,0xFF,0x10,0x08,0x04,0x02,0x01,0xAA,0x55,0x55,0xAA};
uint16_t cb = numvals; // Loop counter
uint8_t *ptr = pixels; // Pointer to next val
uint8_t b;
uint8_t *port;
uint8_t pinMask = (0x1 << DATA_IN); // maschera sul bit da tx
uint8_t Maschera, Nbit ;
uint8_t hi, lo;
void setup()
{
pinMode(DATA_IN, OUTPUT);
digitalWrite(DATA_IN, LOW);
port = &PORTD;
hi = *port | pinMask;
lo = *port & ~pinMask;
Maschera = 0x80; // preset maschera bit
Nbit=8;
Serial.begin(115200);
Serial.print("PORT "); Serial.print(*port, HEX);
Serial.print(" pinMask "); Serial.print(pinMask, HEX);
Serial.print(" hi "); Serial.print(hi, HEX);
Serial.print(" lo "); Serial.print(lo, HEX);
b = *ptr++; // val corrente da trasmettere
Serial.print(" b "); Serial.println(b, HEX);
asm volatile(
"cli" "\n\t" // 1 cli = globai Interrup disble
"Ciclo:" "\n\t" // Clk Descrizione
"out %[port], %[hi]" "\n\t" // 1 Alza lo stato del bit da tx
**"and %[val], %[Maschera]" "\n\t" // 1-2 Verifica se il bit mascherato è 1 o 0**
"breq Ciclo_0" "\n\t" // 2 ... se "0" salta a Ciclo_0
"brne Ciclo_1" "\n\t" // 2 ... se "1" salta a Ciclo_1
"Ciclo_0:" "\n\t" //
"call Bit_0" "\n\t" // 1-2 Chiama la Sub Bit_0
"jmp Ciclo_com" "\n\t" // 2 salta al punto comune
"Ciclo_1:" "\n\t" //
"call Bit_1" "\n\t" // 1-2 Chiama la Sub Bit_1
"Ciclo_com:" "\n\t" //
**"lsr %[Maschera]" "\n\t" // 1 Genera la nuova maschera**
"dec %[Nbit]" "\n\t" // 1
"brne Ciclo" "\n\t" // 1 ... se != da 0 ripete ...
"sbiw %[count], 1" "\n\t" // 2 ... aggiorna il contatore dei val da tx
"breq Fine" "\n\t" // 2 ... se non ce ne sono termina
"ld %[val], %a[ptr]+" "\n\t" // 2 altrimenti carica il nuovo val da tx
"ldi %[Maschera], 0x80" "\n\t" // 1 Riparte con la maschera iniziale
"ldi %[Nbit], 0x08" "\n\t" // 1
"jmp Ciclo" "\n\t" // 2 ...e ripete il ciclo
"Bit_0:" "\n\t" //
"nop" "\n\t" // 1 nop
"out %[port], %[lo]" "\n\t" // 1 Abbassa lo stato del bit da tx
"nop" "\n\t" // 1 nop
"nop" "\n\t" // 1 nop
"ret" "\n\t" // 4 ritorno dalla sub.
"Bit_1:" "\n\t" //
"nop" "\n\t" // 1 nop
"nop" "\n\t" // 1 nop
"nop" "\n\t" // 1 nop
"nop" "\n\t" // 1 nop
"nop" "\n\t" // 1 nop
"out %[port], %[lo]" "\n\t" // 1 Abbassa lo stato del bit da tx
"ret" "\n\t" // 4 ritorno dalla sub.
"Fine:" "\n\t" //
"sei" "\n" // 1 cli = globai Interrup disble
: [count]"+w"(cb),[val]"+r"(b),[Maschera]"+r"(Maschera),[Nbit]"+r"(Nbit),[hi]"+r"(hi), [lo]"+r"(lo)
: [port] "I"(_SFR_IO_ADDR(PORTD)), [ptr]"e"(ptr)
: );
}
void loop()
{
}