Hallo zur Webseite von
DL1DMW





Microchip Series 1 Controller:
Der ATtiny3216

Nachdem Atmel vor einigen Jahren an Microchip gegangen ist, erschienen neue Mikrocontroller auf der Basis des Atmel-RISC-Kerns mit erweiterten Funktionen aus der Microchip-PIC-Serie, zum Beispiel die ATTiny-Serie 1. Wir betrachten die erweiterten Möglichkeiten am Beispiel eines ATTiny3216 im Vergleich zu dem bekannten ATMega328, der unter anderem im beliebten Arduino UNO verbaut ist.



Bild 1: Eine Selbstbau-Experimentierplatine mit ATTiny3216.

Beide Controller basieren auf denselben CPU-Kern und unterscheiden sich nicht in der Speicherausstattung (32 KB Flash, 2KB SRAM, 256 Bytes internes EEPROM). Beim ATMega328 ist die Bedeutung jedes Pins am Gehäuse in seiner Funktion festgelegt. Je nach Nutzung der internen Peripherie kann das nachteilig sein, weil bestimmte Pins mehrfach belegt sind. Beim ATTiny3216 ist es möglich, bestimmte Aus- bzw. Eingänge mittels eines Portmultiplexers auf alternative Pins zu verlegen. Nutzt man Beispielsweise die Funktion des Periphären Touch Controllers (PTC), kollidieren die Pins mit dem I2C-Bus, genauer die Signale SDA und SCL. Beide lassen sich auf andere Pins verlegen. Auf dieselbe Art lassen sich auch die SPI-Signale vom PortA zum PortC verlegen. Das geschieht bequem per Softwarebefehl.

Ebenso per Befehl in der Anwendersoftware lassen sich ein Software-Reset auslösen und die Taktfrequenz auf interne Oszillatoren umschalten, aber auch einen vorgeschalteten Prescaler (Teiler) programmieren. Den internen 16/20-MHz-Oszillator stellt man noch wie gehabt per Fusebit auf den gewünschten Wert, den Teiler dann per Software. Interessant ist der 32-kHz-Oszillator, der einem RTC-Timer (RTC = Real Time Clock) zugeordnet werden kann. Für Anwendungen mit einer Spannungsversorgung aus Batterien ist der 32-kHz-Oszillator wertvoll, um den Stromverbrauch gering zu halten. Wartet der Prozessor beispielsweise bei 32 kHz Takt – genauer gesagt exakt 32768 Hertz - auf einen externen Interrupt, schaltet man die Taktfrequenz des Controllers kurzfristig hoch, das Programm erledigt einen Job, schaltet zurück auf 32 kHz und legt sich wieder schlafen. Es geht sogar noch langsamer: Kombiniert man den 32-kHz-Oszillator mit dem Prescaler, kann man die Taktfrequenz bis auf 500 Hz absenken – und damit auch den Stromverbrauch. Mit dem ATTiny3216 ist es möglich, je nach dem, welche internen Funktionsblöcke man benötigt, den Stromverbrauch bis unter 1µA zu reduzieren.


<- Bild 2: Pinbelegung des ATTiny3216 im SOIC-Gehäuse. Quelle: Datenblatt.



Der Prozessor verfügt über ein Eventsystem: Ein Ereignis, z.B. ein externes Signal löst einen Interrupt aus, dieser wiederum stößt eine Aktion an, ohne das diese explizit programmiert werden muss. Man konfiguriert das flexible Eventsystem und löst nach z.B. einer Änderung von High nach Low an einem Pin beispielsweise das Messen einer analogen Spannung aus. Im Eventsystem werden zwei Funktionsblöcke direkt – also ohne Beteiligung des CPU-Kerns – miteinander verbunden. Auch Timer können als Auslöser eines Events dienen.

Die funktionelle Ausstattung ist üppig, betrachten wir die Timer: Drei 16-Bit-Timer, ein 12-Bit-Timer und ein weiterer 16-Bit-Timer speziell für die Real Time Clock (RTC) warten auf den Programmierer. Hinzu kommt der Watchdog-Timer, den der ATMega328 auch kennt. Gegenüber dem ATMega328 wurde die Anzahl der Analog-Digital-Wandler von eins auf zwei erhöht, die Auflösung von 10 Bit wurde beibehalten. Neu sind drei Digital-zu-Analogwandler (DAC) mit 8 Bit Auflösung, um eine analoge Spannung zu erzeugen. Das SPI-Interface lässt sich wahlweise als Master oder Slave betreiben. Das Two-Wire-Interface (TWI oder auch I2C) beherrscht den Standard-, Fast- und Fast-Mode-plus. Ein UART (serielle Schnittstelle) ist obligatorisch und lässt sich synchron wie asynchron betreiben.
Bild 3: Das Blockdiagramm illustriert alle wichtigen Funktionsgruppen. Quelle: Datenblatt.

Der Controller wird, wie auch der ältere Bruder, mit dem Atmel Studio 7 programmiert und mit dem Programm bestückt (geflasht). Gegenüber dem ATMega328 hat sich das Programmierinterface (ISP) verändert. Der ATTiny3216 und seine Brüder der Series 1 werden nun über einen einzigen Pin mit der Bezeichnung UPDI programmiert und auch das Debugging funktioniert über diesen einem Pin. UPDI bedeutet Unified Program and Debugging Interface, zu deutsch etwa: Vereintes Programmier- und Fehlerbehebungs-Interface.
Als Programmiergerät (zum flashen des Controllers) verwendet man beispielsweise den Atmel ICE, es gibt im Internet jedoch auch eine preiswertere Lösung, die einen Arduino Mikro als UPDI-Programmer implementiert [2].


Zum Einstieg: Codeschnipsel

Jeder Pin des Prozessors lässt sich natürlich als digitalen Aus- oder Eingang verwenden. Ein interner Pull-up-Widerstand ist zuschaltbar und: jeder Pin ist interruptfähig! Die Syntax der Befehle zur Konfiguration hat sich gegenüber den ATMega328 ein wenig geändert – in Richtung Übersichtlichkeit:

PORTA.DIRSET = PIN3_bm // PortA.3 = Output
PORTA.DIRCLR = PIN4_bm; // PortA.4 = Input

Die neue Syntax _bm bei der Angabe des Pins bedeutet Bitmask. Es gibt noch _bp und bedeutet Bitposition sowie einige andere. In den beiden Zeilen oben werden nur dieses Bit im Richtungsregister des Ports A verändert. Möchte man die Ausgabe eines Pins auf High oder Low einstellen, schreibt man:

PORTA.OUTSET = PIN3_bm; // PORTA.3 = High
PORTA_OUTCLR = PIN3_bm; // PORTA.3 = Low

Nun lesen wir einen digitalen Wert von einem Port ein:

i = PORTA.IN; // lese den ganzen Port A
j = PORTA.IN & PIN4_bm; // lese Bit 4 aus Port A

Einfach ist es, den Pegel eines Pins zu verändern, zu toggeln. Dazu schreibt man:

PORTA.OUTTGL = PIN3_bm; // Toggle Port A, Pin3

Der folgende Code-Schnipsel schaltet je nach Einstellung von F_CPU (festlegung der Taktfrequenz) den Prescaler auf die gewünschte Taktfrequenz des Controllers:

#define F_CPU 3333333UL

void CLKCTRL_init(void)
{
#if (F_CPU == 1000000UL) /* 1MHz, 16/16, Fuse: 16 MHz */
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_16X_gc | CLKCTRL_PEN_bm);
#endif

#if (F_CPU == 20000000UL) /* Fuse: 20MHz */
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0 << CLKCTRL_PEN_bp);
#endif

#if (F_CPU == 3333333UL /* 3.3 MHz bei Fuse = 20 MHz / 6 = 3.3 MHz*/
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_6X_gc | CLKCTRL_PEN_bm
#endif
}

Und nun die Umschaltung auf den internen 32-kHz-Taktoszillator:

void Main_Clock_32_kHz(void)
{
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCULP32K_gc);
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0 << CLKCTRL_PEN_bp); // Prescaler aus
}

Nun wird es langsam: Diese Zeilen schalten die MAIN_CLK auf den internen Oszillator 32 kHz mit einem Prescaler von 32 = 32 / 32 = 1 kHz:

void Main_Clock_1_kHz(void)
{
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCULP32K_gc);
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_32X_gc | CLKCTRL_PEN_bm);
}

Es geht aber noch langsamer, hier einmal ein Takt von nur 500 Hertz!. Diese Zeilen schalten die MAIN_CLK auf den internen Oszillator 32 kHz mit Prescaler 64 = 32 / 64 = 0.5 kHz
void Main_Clock_0_5_kHz(void)
{
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCULP32K_gc);
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_64X_gc | CLKCTRL_PEN_bm);
}

Je langsamer der Prozessor getaktet ist, desto weniger Strom konsumiert dieser. Das Tolle ist, dass alles per Software passiert. Man „springt“ von Taktfrequenz zu Taktfrequenz, je nach Anwendung und Vorgabe, wie viel Strom man sparen möchte bzw. welche Funktionen (z.B. SPI) eine Mindesttaktfrequenz benötigen. Der Controller sorgt intern dafür, dass der Übergang zur schnelleren / langsameren Frequenz ohne Programmabsturz passiert.

Nun führen wir einen Reset per Software durch. Hierzu muss ein „Freischalt-Code“ gesetzt werden (0xD8), damit der Controller den Befehl akzeptiert, denn einige Register sind besonders gegen Überschreiben geschützt:

void SoftwareReset()
{
CPU_CCP = 0xD8;
RSTCTRL_SWRR = 1;
}

Mit Hilfe von <eeprom.h> gestaltet sich das Schreiben und Lesen des internen EEPROMS sehr einfach und unterscheidet sich nicht von dem Code, den man für einen ATMega328 schreiben würde. Dafür sorgt die eingebundene .h-Datei. Es muss also nicht alles neu erarbeitet werden! Der Code sieht so aus:

#include <avr/eeprom.h>

uint8_t b;

uint8_t readEeprom(uint8_t adr) // Adresse angeben
{
while(eeprom_is_ready() == 0);
return eeprom_read_byte((const uint8_t *) adr);
}

void writeEeprom(uint8_t adr, uint8_t value)
{
if(readEeprom() != value)
{
while(eeprom_is_ready() == 0);
eeprom_write_byte((uint8_t *) adr, value);
}
}

void main()
{
b = readEeprom(10); // lesen von Adresse 10
writeEeprom(10, 0x55); // Schreiben auf Adresse 10, Wert 0x55
}


Aussicht

Mit ein wenig Konsultation des Datenblattes und einigen Beispielprogrammen gelingt der Umstieg auf die neue ATTiny Series 1 recht gut. Diese Bausteine bieten einige Vorteile, insbesondere qualifizieren sie sich für Anwendungen mit Batteriebetrieb. Der ATTiny3216 ist weitaus flexibler als der „alte“ ATmega328. Dieser Beitrag kann nur wenige Zeilen Code zu Papier bringen, alles andere würde den Umfang sprengen. Beispielprogramme für die Timer, I2C, SPI und zum AD- und DA-Wandler oder eine Funktion, um die eigene Spannungsversorgung des Controllers zu messen, und das ohne zusätzliche externe Bauelemente wie einen Spannungsteiler, findet man in der Datei attiny3216.zip ( ca. 1 MB) unten zum Download. Die dort abgelegten Projekte lassen sich direkt in das Atmel Studio 7 laden und kompilieren. Dazu kopieren Sie eine der Zip-Dateien in das Atmel Studio 7-Verzeichnis (meist LW:\Benutzer\Dokumente\Atmel Studio\7.0) und packen es aus. Starten Sie nun Atmel Studio 7 und laden das Projekt.

Haben Sie Interesse an der Programmierung des ATTiny3216 per UPDI mit einem Arduino UNO? Dann lesen Sie
hier weiter!

Literatur/Verweise:
[1] Infos zu ATTiny3216:
https://www.microchip.com/wwwproducts/en/ATTINY3216
[2] Alternativer UPDI-Programmer:
https://github.com/MCUdude/microUPDI
[3] Alternativer UPDI-Programmer mit Arduino UNO:
https://github.com/ElTangas/jtag2updi

Datei attiny3216.zip laden






Mehr Zeugs
  • Schaun mer mal
  • Moin
  • Bast scho

Hier gibt es was zu lesen

Adresse etc.

  • Op: Michael, DL1DMW
  • ITU Region 1, Zone 14, DL, JO41CO
  • Bad Sassendorf
  • NRW / Germany