/*
Protokolladapter IAI <=> BiSS/EnDat
Aus Sicht von BiSS/EnDat ist der Mikrocontroller ein Slave!
Daher ist hier MOSI ein Eingang und MISO ein Ausgang, anders als gewohnt.
Hardware: ATtiny2313
Pin Port Funktion
1 (PA2) !RESET Reset; ISP
2 PD0 RxD IAI-Geber via MAX485
3 PD1 TxD IAI-Geber via MAX485
4 (PA1) XTAL2 Quarz 20 MHz
5 (PA0) XTAL1 Quarz 20 MHz
6 PD2 (!CS) Debugport
7 PD3 (SDI) Debugport
8 PD4 (SDO) Debugport
9 PD5 (SCK) Debugport
10 GND
11 PD6 Taste low-aktiv ohne ext. Pullup
12 PB0 Gelbe LED, high-aktiv
13 PB1 Grüne LED, high-aktiv
14 PB2 (SDE) BiSS/EnDat Sendefreigabe high-aktiv
15 PB3 (!RE) BiSS/EnDat Empfängerfreigabe low-aktiv
16 PB4 (TE) IAI-Geber Sendefreigabe high-aktiv
17 PB5 DI BiSS/EnDat Datenempfang; ISP:MOSI
18 PB6 DO BiSS/EnDat Datensenden; ISP:MISO
19 PB7 USCK BiSS/EnDat Takteingang; ISP:SCK
20 Ucc
RS485-Protokoll:
Der IAI-Controller schickt "0x1A" alle 100 µs (10 kHz), Dauer 4 µs
Nach 4 µs Pause schickt die Achse 11 Byte Antwort:
"0x1A,0x00,posLo,posMi,posHi,k1,k2,k3,k4,k5,chkxor"
Weitere Kommunikation beim Hochlauf wird ignoriert
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/eeprom.h>
#include <avr/fuse.h>
#include <avr/signature.h>
FUSES={
0b11111111, // Quarz 20 MHz, ganz langsam hochfahren, kein Taktteiler
0b11011001, // SPI-Programmiermöglichkeit bleibt erhalten, BrownOut bei 4,3 V(!)
0b11111111, // unverändert
};
typedef unsigned char byte;
#define NOINIT __attribute__((section(".noinit")))
//EMPTY_INTERRUPT(TIMER0_OVF_vect)
//static volatile byte bissbuf[32];
//volatile register byte bbi asm("r2");
//volatile register byte bbc asm("r3");
static volatile byte iaibuf[32] NOINIT;
static volatile byte iairecvidx;
//volatile register byte iairecvcnt asm("r7");
const byte iairecvcnt=11;
//volatile register byte msk asm("r6");
//volatile register byte iaisendcnt asm("r8"); // Sende-Byte-Abwärtszähler für IAI
//volatile register byte iaisendidx asm("r9");
#if 0
static void iai_query() {
iairecvidx=0;
// iairecvcnt=11;
iaibuf[0]=0x1A;
iaisendidx=0;
iaisendcnt=1;
PORTB|= 0b00010000; // MAX485-Leitungstreiber aktivieren
UCSRB = 0b00101000; // Senden mit Interrupts
} // der Rest passiert interruptgesteuert
ISR(USART_UDRE_vect) {
UDR=iaibuf[iaisendidx];
if (++iaisendidx==iaisendcnt) UCSRB = 0b01001000; // Ab jetzt Interrupt wenn Sendeschieberegister leer
}
ISR(USART_TX_vect) { // Ohren auf Empfang stellen
PORTB&=~0b00010000; // MAX485 Sendefreigabe wegnehmen
UCSRB = 0b10010000; // Empfänger aktivieren mit Interrupts und Sender aus
}
#endif
ISR(USART_RX_vect,ISR_NAKED) {
PORTD|=0x08;
if (UCSRA&0x10) PORTB&=~0x02; // Falsche Baudrate
byte b=UDR;
byte r=iairecvidx;
if (r<2 && b!=0x1A) {
r=0; // von vorn
}else{
iaibuf[r]=b;
if (r==0 && b==0x1A) PORTB|=0x02; // Grüne LED ein
if (r==1 && b==0x1A) PORTB|=0x01; // Gelbe LED ein
if (++r==12) {
// UCSRB = 0; // alles aus, Puffer voll
PORTB&=~0x01; // Gelbe LED aus
GPIOR0|=0x01; // Softwareinterrupt: P
r=0;
}
}
iairecvidx=r;
reti();
}
#if 0
#define USIBR _SFR_IO8(0)
ISR(USI_OVERFLOW_vect) {
USIDR=bissbuf[bbi]; // Hm, erst schreiben, dann lesen, oder andersherum??
bissbuf[bbi]=USIBR;
USISR|= 0b01000000; // Interrupt löschen
if (++bbi==bbc) {
// * Anfrage dekodieren
PORTB|= 0b00000100; // antworten
// * Antwort bereitstellen
}
}
#endif
static int debugSPI(int v) {
PORTD&=~0x04; // Debug-!CS Low
byte i=16;
do{
if (v<0) PORTD|=0x10; else PORTD&=~0x10; // Debug-SDO
PORTD|=0x20; // Debug-SCK High
v+=v;
if (PIND&0x08) v|=1; // Debug-SDI
PORTD&=~0x20; // Debug-SCK Low
}while(--i);
PORTD|=0x04; // Debug-!CS High
return v;
}
void debugPosOut() {
#if 1
unsigned pos;
asm(
" ldd %B0,%a1+5\n"
" ror %B0\n" // Bit 0 ausschieben
" ldd %B0,%a1+4\n"
" ror %B0\n"
" ldd %A0,%a1+3\n"
" ror %A0\n"
:"=&r"(pos):"b"(iaibuf));
debugSPI(pos);
#else
debugSPI(iaibuf[4]<<8|iaibuf[3]);
#endif
}
int main() {
MCUCR = 0b00100000; // Sleep aktivieren
DDRB = 0b01011111; // PWM als Ausgänge
PORTB = 0b00000010; // keinerlei Pullups, alles Low; grüne LED ein
DDRD = 0b00111110;
PORTD = 0b01001101;
// IAI-Seite: Baudratenregister ist bereits 0, UCSRC stimmt schon (8 bit)
UCSRA = 0b00100010; // Double-Speed = 2,5 MBaud
// UCSRB = 0b00011000; // Sender und Empfänger sowie Interrupts freigeben
// Testweise: 2× 0x1A empfangen und Telegramm aufzeichnen
iairecvidx=0;
// iairecvcnt=12;
UCSRB = 0b10010000; // UART-Empfänger aktivieren mit Interrupts
// BiSS/EnDat-Seite
// USICR = 0b01011000; // Daten einlesen bei steigender Taktflanke, Wechsel der Ausgabe bei fallender Flanke, Interrupts
sei();
for(;;) {
PORTD&=~0x08; // an Debug-SDI Schlaf/Wachzustand anzeigen
sleep_cpu();
PORTD|= 0x08;
if (GPIOR0&0x01) {
GPIOR0&=~0x01;
debugPosOut();
}
}
}
Detected encoding: UTF-8 | 0
|