Einführung der mobilen FPGA iCE40 UltraPlus-Entwicklungsplattform von Lattice Semiconductor

Einführung



Guten Tag, Freunde! Kürzlich haben wir bei der Arbeit eine brandneue iCE40 UltraPlus Mobile Development Platform-Karte von Lattice Semiconductor erhalten. Laut den Entwicklern auf der offiziellen Website von iCE40 UltraPlus ist das MDP ein Board, das 4 iCE40 UltraPlus-FPGAs enthält, von denen jedes seinen eigenen Satz von Peripheriegeräten steuert. Das Set enthält:



  • mobiles Display mit einer Auflösung von 240x240 mit MIPI-DSI-Schnittstelle;
  • Bildsensor mit einer Auflösung von 640 x 480 (OVM7692);
  • Low-Power-Mikrofone in Höhe von 4 Stück;
  • BLE-Modul zur drahtlosen Datenübertragung;
  • programmierbarer SPI-Flash-Speicher;
  • Packung verschiedener Sensoren (Druck, Kompass, Gyroskop und Beschleunigungsmesser);
  • Nun, alle Arten von Knöpfen und Glühbirnen.


Das ganz Coole an diesem Wal ist, dass Sie mithilfe spezieller Softwarepakete neuronale Netze bereitstellen können, um mit Video und Ton zu arbeiten. Ganz zu schweigen von der Tatsache, dass Gitter-FPGAs stromsparend, klein und recht billig sind.



UltraPlus MDP







Blinken Sie als Testfall die RGB-LED (D13 im Diagramm, im Bild links rot hervorgehoben). Nach Durchsicht der Dokumentation schließen wir, dass die LED von der FPGA-Nummer U3 gesteuert wird (im Bild rechts rot hervorgehoben). Aus der Dokumentation erfahren wir auch, dass die LED von einem eingebauten PWM-Modulator und einem aktuellen Treiber gesteuert wird.



Wir nehmen diese Informationen zur Kenntnis.



Das Board einrichten und ein Programm schreiben



Auf der Karte befindet sich eine Gruppe von Jumpern, mit denen Sie das FPGA auswählen können, das geflasht werden muss, um mit der ausgewählten Gruppe von Peripheriegeräten zu arbeiten. Wir sind an drei Gruppen von Steckbrücken interessiert, die für das Hochziehen der Stromversorgung der LED und das Programmieren des gewünschten FPGA verantwortlich sind.







Das Verfahren ist wie folgt:



  1. Stellen Sie den Schalter SW5 auf ON / OFF
  2. Zwei Jumper auf J19 horizontal
  3. J26 , 1-2 3-4 ( . , )
  4. J17, J25, J27 9-10 ( )


Ja, ich verstehe, es ist alles langweilig, aber ohne es wird es nicht funktionieren.



Um den Taktsignalgenerator anzuschließen, muss der Jumper J23 auf Position 2-3 gesetzt werden (die Nummerierung erfolgt von oben).







Nun das Programm. Um eine Bitdatei für die iCE40 UltraPlus MDP-Firmware zu erstellen, benötigen Sie die Entwicklungsumgebung Lattice iCE cube 2 ( Link zur Produktseite ) und das Programmier- und Bereitstellungstool Board selbst zu flashen . Das Produkt ist lizenziert, aber nach der Registrierung kann die Lizenz hier bezogen werden: www.latticesemi.com/Support/Licensing/DiamondAndiCEcube2SoftwareLicensing/iceCube2



Der Editor in der IDE ist sehr unpraktisch, daher habe ich in Sublime Text geschrieben, aber für jeden seinen eigenen.



Hier ist ein allgemeines Schema, das ein Verständnis dafür gab, was und wo zu tun ist:







Der PWM-Modulator und der aktuelle Treiber, die ich bereits erwähnt habe, sind also aufgetaucht. Diese beiden Geräte sind interne Module. Es ist notwendig, ein Logiksteuergerät zu schreiben und Daten zu senden, damit die gesamte Küche ordnungsgemäß funktioniert. Beginnen wir in der richtigen Reihenfolge und beschreiben die "Black Box":



entity DriverRGB is
	port (
		-- RGB Led:
		LED0 	: out std_logic;
		LED1 	: out std_logic;
		LED2 	: out std_logic );
end DriverRGB;


Die Synchronisierungsinitialisierung fehlt in der Blackbox. Hierzu wird ein internes Modul verwendet, das wie folgt deklariert wird:



-- Generator clock:
component SB_HFOSC is
	generic (
		CLKHF_DIV	: string := "0b00" );
	port (
		CLKHFPU	: in std_logic;
		CLKHFEN	: in std_logic;

		CLKHF 	: out std_logic );
end component;


BildDieses Modul kann ein Signal mit Frequenzen von 48 MHz, 24 MHz, 12 MHz und 6 MHz erzeugen. Der Parameter CLKHF_DIV ist für den Frequenzteilungsfaktor verantwortlich ("0b00", "0b01", "0b10" bzw. "0b11"). CLKHFPU und CLKHFEN ermöglichen die Arbeit des Moduls. CLKHF - Taktsignal.



Als nächstes deklarieren wir den PWM-Modulator und den aktuellen Treiber:



-- Embedded PWM IP:
component SB_LEDDA_IP is
	port (
		LEDDCS		: in std_logic;
		LEDDCLK		: in std_logic;
		LEDDDAT7	: in std_logic;
		LEDDDAT6	: in std_logic;
		LEDDDAT5	: in std_logic;
		LEDDDAT4	: in std_logic;
		LEDDDAT3	: in std_logic;
		LEDDDAT2	: in std_logic;
		LEDDDAT1	: in std_logic;
		LEDDDAT0	: in std_logic;
		LEDDADDR3	: in std_logic;
		LEDDADDR2	: in std_logic;
		LEDDADDR1	: in std_logic;
		LEDDADDR0	: in std_logic;
		LEDDDEN 	: in std_logic;
		LEDDEXE		: in std_logic;
		LEDDRST		: in std_logic;

		PWMOUT0		: out std_logic;
		PWMOUT1		: out std_logic;
		PWMOUT2		: out std_logic;
		LEDDON		: out std_logic );
end component;


-- RGB Driver:
component SB_RGBA_DRV is
	generic (
		CURRENT_MODE	: string := "0b0";
		RGB0_CURRENT	: string := "0b000000";
		RGB1_CURRENT	: string := "0b000000";
		RGB2_CURRENT	: string := "0b000000" );
	port (
		CURREN		: in std_logic;
		RGBLEDEN	: in std_logic;
		RGB0PWM		: in std_logic;
		RGB1PWM		: in std_logic;
		RGB2PWM		: in std_logic;

		RGB0 		: out std_logic;
		RGB1 		: out std_logic;
		RGB2 		: out std_logic );
end component;


BildDer PWM-Modulator muss die Adresse und Daten einspeisen, die für die LED-Betriebsarten und einige Steuersignale verantwortlich sind. Die Ausgänge werden dann von einem RGB-Stromtreiber verarbeitet, der bereits die LED leuchtet.


Der aktuelle Treiber verarbeitet die Daten vom PWM-Modulator und passt den der LED zugeführten Stromwert an. Die Parameter RGB0_CURRENT, RGB1_CURRENT, RGB2_CURRENT legen die Strommenge für jede Farbe fest. CURRENT_MODE - Power-Modus (voll oder halb).



Bild



Ja, cool. Es gibt Adressen, es gibt Daten. Nun, was soll ich ihnen schicken? Im Allgemeinen geben die Lattice-Entwickler in ihrer Dokumentation eine ziemlich detaillierte Beschreibung, die jedoch recht umfangreich ist. Ich werde versuchen, alles zur Klarheit in ein paar Zeilen Beschreibung und Code zusammenzufassen.



Der PWM-Modulator erwartet 9 Adressen. Jeder von ihnen ist für eine bestimmte Funktion verantwortlich, damit die LED funktioniert. Unten finden Sie eine Tabelle mit den Werten und Namen der Adressen:







Um Daten zu senden, implementieren wir die Finite-State-Maschine:



type LED_Driver is (IDLE, LEDDBR, LEDDONR, LEDDOFR, LEDDBCRR, LEDDBCFR, LEDDPWRR, LEDDPWRG, LEDDPWRB, LEDDCR0, DONE);


Der erste Schritt besteht darin, Daten in das LEDDBR-Register zu schreiben. Es speichert den Wert für die PWM-Taktfrequenz. Es wird wie folgt betrachtet:



Register Value N = Fsys/64kHz-1


Die Struktur des Datensatzes sieht folgendermaßen aus: Die







beiden höchstwertigen Bits für den Frequenzwert werden addiert, wenn wir uns dem LEDDCR0-Register zuwenden.



when LEDDBR =>
		led_en			<= '1';
		led_cs			<= '1';
		led_exe			<= '0';
		LEDD_ADR		<= "1001";
		DAT_Bits(7 downto 0)	<= "11101101"; --     (   )
		PWM_state_next		<= LEDDONR;


Das LEDDONR-Register zeichnet die Zeit auf, in der die LED aktiv ist. Die Dokumentation enthält eine Entsprechungstabelle, zu der ein Satz von Bits zu einer bestimmten LED-Brennzeit gehört.



when LEDDONR =>
		led_en			<= '1';
		led_cs			<= '1';
		led_exe			<= '0';
		LEDD_ADR		<= "1010";
		DAT_Bits(7 downto 0)	<= "00010001"; --    (0.5 c)


Das LEDDOFR-Register enthält Daten darüber, wie lange die LED inaktiv ist. Genau die gleichen Werte wie in LEDDONR.



when LEDDOFR =>
		led_en			<= '1';
		led_cs			<= '1';
		led_exe			<= '0';
		LEDD_ADR		<= "1011";
		DAT_Bits(7 downto 0)	<= "00010001"; --    (0.5 c)
		PWM_state_next		<= LEDDBCRR;


LEDDBCRR - Daten zur Dauer des LED-Soft-Ons.



when LEDDBCRR =>
		led_en			<= '1';
		led_cs			<= '1';
		led_exe			<= '0';
		LEDD_ADR		<= "0101";
		DAT_Bits(7)		<= '1'; --   ()
		DAT_Bits(6)		<= '1'; --   
		DAT_Bits(5)		<= '1'; --    
		DAT_Bits(4)		<= '0'; -- RESERVED
		DAT_Bits(3 downto 0)	<= "0011"; --   (0.5 )
		PWM_state_next		<= LEDDBCFR;


LEDDBCRR - Daten zur Dauer des LED-Soft-Offs.



when LEDDBCFR =>
		led_en			<= '1';
		led_cs			<= '1';
		led_exe			<= '0';
		LEDD_ADR		<= "0110";
		DAT_Bits(7)		<= '1'; --   () (disable/enable)
		DAT_Bits(6)		<= '0'; -- PWM Range Extend
		DAT_Bits(5)		<= '1'; --    
		DAT_Bits(4)		<= '0'; -- RESERVED
		DAT_Bits(3 downto 0)	<= "0011"; --   (0.5 )
		PWM_state_next		<= LEDDPWRR;


Die Register LEDDPWRR, LEDDPWRG und LEDDPWRB zeichnen die Daten zur Helligkeit der roten, blauen und grünen LEDs auf. Der Helligkeitswert wird als Prozentsatz nach der folgenden Formel berechnet:



ADC(%) = PulseWidth/256


Unterschiedliche Helligkeitswerte ergeben daher eine Mischung aus Farben, sodass Sie herumspielen und Ihr Ideal erreichen können.



when LEDDPWRR =>
		led_en			<= '1';
		led_cs			<= '1';
		led_exe			<= '0';
		LEDD_ADR		<= "0001";
		DAT_Bits(7 downto 0)	<= "00000001"; -- RED Pulse Width
		PWM_state_next		<= LEDDPWRG;


when LEDDPWRG =>
		led_en			<= '1';
		led_cs			<= '1';
		led_exe			<= '0';
		LEDD_ADR		<= "0010";
		DAT_Bits(7 downto 0)	<= "11111111"; -- GREEN Pulse Width
		PWM_state_next		<= LEDDPWRB;


when LEDDPWRB =>
		led_en 			<= '1';
		led_cs			<= '1';
		led_exe			<= '0';
		LEDD_ADR		<= "0011";
		DAT_Bits(7 downto 0)	<= "00011111"; -- BLUE Pulse Width
		PWM_state_next		<= LEDDCR0;


Nun, das letzte Register LEDDCR0 zeichnet die Aktivierungsinformationen und die zwei höchstwertigen Bits der PWM-Taktsignalfrequenz auf:



when LEDDCR0 =>
		led_en			<= '1';
		led_cs			<= '1';
		led_exe			<= '0';
		LEDD_ADR		<= "1000";
		DAT_Bits(7)		<= '1'; --   ()
		DAT_Bits(6)		<= '1'; -- Flick Rate Select Bit (125/250 Hz)
		DAT_Bits(5)		<= '0'; --    (1/0)
		DAT_Bits(4) 		<= '0'; --      
		DAT_Bits(3)		<= '1'; -- Blinking Sequence Quick Stop Enable Bit
		DAT_Bits(2)		<= '0'; -- PWM Mode Selection Bit
		DAT_Bits(1 downto 0)	<= "10"; --    
		PWM_state_next		<= DONE;


Implementierungsbeispiele



RGB







Lila / Weiß







Zusammenfassen



Nun, das ist alles. Durch Ändern der Parameter können Sie einen schönen Atmungseffekt der LED mit unterschiedlichen Farben und Helligkeiten erzielen, indem Sie die Werte in den Registern LEDDPWRR, LEDDPWRG, LEDDPWRB oder den aktuellen Wert des RGB-Treibers ändern. Unten finden Sie Links zum Code auf GitHub und alle erforderlichen Dokumentationen.



In Zukunft plane ich, andere Brötchen zu testen und wenn möglich hier zur Überprüfung zu stellen.



Evaluierungskarte Benutzerhandbuch Code des

iCE40 LED-Treibers




All Articles