Archives mensuelles : août 2021

Réception du kit Tang Nano 4K

La désormais célèbre société chinoise Sipeed vient de sortir un tout petit kit de développement autour d’un FPGA Gowin et muni d’une sortie HDMI ainsi que d’une entrée caméra : la Tang Nano 4K.

Principaux périphériques disponibles sur la Tang Nano 4K

Et non, elle n’est pas compatible avec des écrans HDMI 4K 😉 Le nom marketing bien choisi désigne le nombre de LUT disponibles.

Le pinout trouvé sur la fiche descriptive d’aliexpress
Attention à certain IO du pinout, qu’il vaut mieux éviter d’utiliser… comme la sortie LED (IOT7A) ! Le document en question semble être celui là

Il est encore difficile de trouver des informations techniques sur cette carte, pourtant disponible (et rapidement livrée) sur aliexpress. Le wiki officiel est encore intégralement en chinois, mais on trouve le code d’exemple sur github. Le schéma de la carte est dispo sur le site de sipeed ici (ou sur le blog du flf si le firewall chinois fait des caprices 😉

À 18$ il n’était pas question de passer à coté, j’ai donc commandé une version avec caméra OV2640 ainsi qu’une version sans caméra :

Les deux kits tels que reçu dans ma boite aux lettres.

Le tout pour une quarantaine d’€.

Branchement

Un câble USB-C est fourni dans la boite, voyons ce qu’il se passe au branchement de la version sans caméra:

 sudo dmesg -c
[34644.177355] usb 1-2.1.1: new full-speed USB device number 14 using xhci_hcd
[34644.283502] usb 1-2.1.1: not running at top speed; connect to a high speed hub
[34644.305274] usb 1-2.1.1: New USB device found, idVendor=0403, idProduct=6010, bcdDevice= 5.00
[34644.305288] usb 1-2.1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[34644.305292] usb 1-2.1.1: Product: JTAG Debugger
[34644.305295] usb 1-2.1.1: Manufacturer: SIPEED
[34644.305298] usb 1-2.1.1: SerialNumber: FactoryAIOT Pro
[34644.311295] ftdi_sio 1-2.1.1:1.0: FTDI USB Serial Device converter detected
[34644.311336] usb 1-2.1.1: Detected FT2232C
[34644.316362] usb 1-2.1.1: FTDI USB Serial Device converter now attached to ttyUSB0
[34644.316513] ftdi_sio 1-2.1.1:1.1: FTDI USB Serial Device converter detected
[34644.316548] usb 1-2.1.1: Detected FT2232C
[34644.322352] usb 1-2.1.1: FTDI USB Serial Device converter now attached to ttyUSB1

La version avec caméra donne exactement la même chose.

Le dmesg de Linux laisse apparaître deux interfaces tty. L’une est certainement un convertisseur jtag pour configurer le FPGA et l’autre une interface uart permettant de communiquer avec l’application comme on a pu le voir avec la Tang Nano «classique».

Si l’on branche un écran au HDMI on voit défiler quelques «pattern» avant de s’arrêter sur un écran vert sur fond bleu.

Pour le moment je n’ai pas réussi à obtenir grand chose de ces deux uarts.

Par la suite j’éditerais cet article pour vous parler de la configuration du FPGA.

Synthèse et configuration

Le plus simple pour commencer avec le kit est d’aller voir les deux projets proposés par Sipeed sur github et de les cloner.

$ git clone https://github.com/sipeed/TangNano-4K-example.git
$ cd TangNano-4K-example/

Deux projets sont disponible dans ce dépôt, vus de loin l’un est pour faire clignoter une led et l’autre pour l’exemple HDMI programmé par défaut dans l’eeprom du kit :

$ ls
dk_video/  led_test/

Pour se faire la main il est donc naturel de commencer par la led.

Il faut d’abord lancer l’IDE officiel de gowin, comme décrit dans l’article de hackable-32 (le plus compliqué avec l’installation de gowin est d’obtenir la licence, après ça roule). Puis ouvrir le fichier de projet fourni nommé project/led_test.gprj et se trouvant dans le répertoire led_test/projet.

Le FPGA du kit se nomme GW1NSR-LV4CQN48PC7/I6 et le code Verilog de clignotement est le suivant. Quand au pinout le voici au format «cst» ci-dessous :

IO_LOC "led" 10;
IO_PORT "led" PULL_MODE=NONE DRIVE=8;
IO_LOC "sys_rst_n" 15;
IO_PORT "sys_rst_n" PULL_MODE=UP;
IO_LOC "sys_clk" 45;
IO_PORT "sys_clk" PULL_MODE=UP;

Le projet est déjà synthétisé, si on souhaite le relancer il suffit de faire un clic-droit «rerun» sur «Synthesize» . Le bitstream est généré au format «fs» et se nomme project/impl/pnr/led_test.fs.

Le kit est désormais reconnu par openFPGALoader:

$ openFPGALoader --detect
write to ram
Jtag frequency : requested 6.00MHz   -> real 6.00MHz  
index 0:
	idcode 0x100981b
	manufacturer Gowin
	family GW1NSR
	model  GW1NSR-4C
	irlength 8

Il suffit donc de programmer le bistrteam (format fs) au moyen de la commande :

$ openFPGALoader led_test/project/impl/pnr/led_test.fs
write to ram
Jtag frequency : requested 6.00MHz   -> real 6.00MHz  
Parse file Parse led_test/project/impl/pnr/led_test.fs: 
Done
DONE
Jtag frequency : requested 2.50MHz   -> real 2.00MHz  
erase SRAM Done
Flash SRAM: [==================================================] 100.00%
Done
SRAM Flash: Success

Et pour l’écrire dans l’eeprom il suffit d’ajouter l’option -f:

$ openFPGALoader ide/gbhdmi/impl/pnr/gbhdmi.fs -f
write to flash
Jtag frequency : requested 6.00MHz   -> real 6.00MHz  
Parse file Parse ide/gbhdmi/impl/pnr/gbhdmi.fs: 
Done
DONE
Jtag frequency : requested 2.50MHz   -> real 2.00MHz  
erase SRAM Done
erase Flash Done
write Flash: [==================================================] 100.00%
Done
CRC check: Success

Le truc se programme et la led clignote.

Le HDMI

Le deuxième projet proposé dans le dépôt concerne le HDMI. Bon si on regarde le contenu du Top on se rend compte qu’il fait bien plus que le simple HDMI puisqu’il pilote également la ram, la Nor et la caméra.

Le générateur de pattern se charge également de générer les signaux de synchronisation vidéo. Mais ce qui nous intéresse particulièrement c’est le bloc qui pilote le HDMI. Ce bloc se prénomme DVI_TX_top et … il est encrypté 🙁

Le bloc est tout de même instanciable au moyen d’une BlackBox chisel. Ce qui permet d’adapter le projet GbVGA en GbHDMI

Pour la vidéo du montage en fonctionnement c’est par là.

La caméra OV2640

Je n’ai pas vu d’exemple de code utilisant la caméra ov2640 avec ce kit pour le moment. Il est probable que ça ne soit pas encore disponible.

Ressources

Convertir du VHDL en Verilog librement avec Yosys et GHDL

Il y a quelques années, nous parlions de l’utilitaire vhdl2vl sur ce blog. Cette solution est intéressante mais limitée car le projet est relativement au point mort.

Depuis quelques mois une solution beaucoup plus «hype» est disponible, alliant le couteau suisse du Verilog Yosys, la référence en simulation libre en VHDL GHDL et le plugin ghdl-yosys-plugin. Cette solution permet dès à présent de convertir la plupart des codes VHDL en Verilog.

Voyons comment faire avec le module de réception uart proposé par nandland : UART_RX.vhd.

$ mkdir vhdlconv
$ cd vhdlconv
$ ls
UART_RX.vhd

Il faut tout d’abord compiler et installer Yosys et GHDL selon la procédure donnée sur les sites respectif.

Un fois fait il faut installer et compiler le plugin ghdl-yosys-plugin comme expliqué sur le dépot. Dans notre cas, cette compilation sera faite dans le répertoire /opt/ghdl-yosys-plugin.

Un fois l’installation effectuée nous pouvons nous lancer dans la conversion avec le plugin :

$ export GHDL_YOSYS_PLUGIN=/opt/ghdl-yosys-plugin/ghdl.so

On élabore le vhdl avec ghdl :

$ ghdl -a UART_RX.vhd 
$ ls
UART_RX.vhd  work-obj93.cf

On lance yosys avec le module ghdl :

$ yosys -m $GHDL_YOSYS_PLUGIN 
...
 |  yosys -- Yosys Open SYnthesis Suite                                       
 |  Copyright (C) 2012 - 2020  Claire Xenia Wolf <claire@yosyshq.com>         
...
 Yosys 0.9+4081 (git sha1 862e84eb, clang 10.0.0-4ubuntu1 -fPIC -Os)

On lit le module fraîchement élaboré:

...
yosys> ghdl UART_RX
1. Executing GHDL.
Importing module UART_RX.

Puis on lance la synthèse :

yosys> proc; opt; fsm; opt; memory; opt;

2. Executing PROC pass (convert processes to netlists).

2.1. Executing PROC_CLEAN pass (remove empty switches from decision trees).
Cleaned up 0 empty switches.

2.2. Executing PROC_RMDEAD pass (remove dead branches from decision trees).
Removed a total of 0 dead cases.

[...]

7.8. Executing OPT_EXPR pass (perform const folding).
Optimizing module UART_RX.

7.9. Finished OPT passes. (There is nothing left to do.)

Et enfin, on peut écrire le Verilog du module converti :

yosys> write_verilog UART_RX.v

8. Executing Verilog backend.
Dumping module `\UART_RX'.

yosys> exit

Le module verilog ainsi généré possède les même noms d’interfaces:

$ head -n 20 UART_RX.v
/* Generated by Yosys 0.9+4081 (git sha1 862e84eb, clang 10.0.0-4ubuntu1 -fPIC -Os) */

module UART_RX(i_Clk, i_RX_Serial, o_RX_DV, o_RX_Byte);
  (* unused_bits = "7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31" *)
  wire [31:0] _00_;
  wire [2:0] _01_;
  wire [6:0] _02_;
  wire _03_;
  wire _04_;
  wire _05_;
  (* unused_bits = "3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31" *)
  wire [31:0] _06_;
  wire [2:0] _07_;
  wire [2:0] _08_;
  wire [2:0] _09_;
  wire [6:0] _10_;
  wire [2:0] _11_;
  wire _12_;
  wire [2:0] _13_;
  wire _14_;

$ head -n 20 UART_RX.vhd
library ieee;
use ieee.std_logic_1164.ALL;
use ieee.numeric_std.all;
 
entity UART_RX is
  generic (
    g_CLKS_PER_BIT : integer := 115     -- Needs to be set correctly
    );
  port (
    i_Clk       : in  std_logic;
    i_RX_Serial : in  std_logic;
    o_RX_DV     : out std_logic;
    o_RX_Byte   : out std_logic_vector(7 downto 0)
    );
end UART_RX;
 
 
architecture rtl of UART_RX is
 
  type t_SM_Main is (s_Idle, s_RX_Start_Bit, s_RX_Data_Bits,

Et même si le code n’est pas très lisible on retrouve ses petits avec le nom des signaux interne du module.

Ce qui est vraiment intéressant ici c’est que le code verilog généré est parfaitement synthétisable avec n’importe quel logiciel de synthèse verilog, on peut également utiliser Verilator pour accélérer nos simulation et enfin il est possible de faire de la preuve formelle avec Yosys.

Plus d’excuse pour ne pas mixer du code VHDL avec du Verilog maintenant puisque tout est convertible en Verilog !

VHDL: afficher du texte au moment de la synthèse vivado

Lorsque l’on essait de faire des modules VHDL génériques, on utilise massivement les paramètres generic map des modules.

Ces paramètres sont utilisés ensuite à la synthèse pour calculer des tailles de tableaux, des constantes et autre structures matérielles générées.

Pour déverminer cette partie du code on a besoin de «voir» les valeurs qui sont calculées. En VHDL il n’y a pas de printf pour ça, mais il y a report utilisé en simulation dans un process :

process is
begin
    report "Affichons des trucs" severity note;
    wait;
end process;

Sauf que nous ne somme pas en simulation, ce process ne sera même pas traité à la synthèse.

Pour pouvoir afficher du texte on peut utiliser les assertions en les mettant systématiquement à faux pour être sur qu’elles soient affichées :

assert false report "Affichons des trucs à la synthèse" severity note;

Mais rien ne s’affiche dans les log à la synthèse Vivado. Ça n’est pas un bug, c’est juste que Xilinx a désactivé ces messages par défaut. Pour les réactiver il suffit de taper cette ligne magique dans la console tcl avant de lancer la synthèse :

set_param synth.elaboration.rodinMoreOptions {rt::set_parameter ignoreVhdlAssertStmts false}

Le message est ensuite visible dans les log:

INFO: [Synth 8-63] RTL assertion: "Affichons des trucs à la synthèse" [plop.vhd:108]

Merci à brimdavis pour le truc.