Nuuo NVRmini NV-4080S/Promise NS4600 (2)

Date: 2025-10-27

Tags: info linux réseau microcontrolleur

Je voulais utiliser le NAS montré dans un article précédent, avec un firmware alternatif, en installant Linux sur un disque dur ou une clé USB.

Pour des raisons inexpliquées, U-Boot n’alimente pas les périphériques SATA ni les périphériques USB lors du démarrage. Ça peut fonctionner avec le firmware original qui n’utilise que la mémoire flash, mais pas dans mon cas : seuls le noyau et l’initrd sont stockés dans la mémoire flash. Le reste de l’OS est stocké sur un disque-dur SATA.

Sauf qu’il est possible de démarrer lorsque l’on interrompt le démarrage automatique de U-Boot, puis que l’on tape une commande pour continuer son exécution.

Test manuel

On branche un PC avec un adaptateur USB-Série 3.3V sur le connecteur J11, on alimente le NAS, et on regarde ce qu’il affiche dans un terminal :

U-Boot 1.3.4 (NS4600p - 014 - 800MHz) (Nov 04 2010 - 14:03:07)

CPU:   AMCC PowerPC 431EXr at 800 MHz (PLB=200, OPB=100, EBC=100 MHz)
    Security/Kasumi support
    Bootstrap Option F - Boot ROM Location NAND (8 bits), booting from NAND
    Internal PCI arbiter disabled
    32 kB I-Cache 32 kB D-Cache
Board: NS4600p - PROMISE 4-bay NAS Target Board, 1*PCIe/1*SATA
I2C:   ready
DRAM:  256 MB
Enclosure: Load fan configurations from VPD
NAND:  128 MiB
eth0 MAC = 00:01:55:31:1f:21
eth1 MAC = 00:00:00:00:00:00
PCI:   Bus Dev VenId DevId Class Int
PCIE1: successfully set as root-complex
        01  00  105a  3f20  0104  00
SCSI:  Net:   ppc_4xx_eth0

Hit Ctrl + C to stop autoboot: 10

Si on n’appuie pas sur Ctrl-C, U-Boot charge le noyau et l’initrd en mémoire, mais n’alimente pas les disques, le noyau ne trouve pas de disque-dur et plante2.

Si on appuie sur Ctrl-C, U-Boot exécute quelques commandes avant de donner un shell :

Leave clock generator PD mode... OK
Leave net PHY PD mode... OK
Turn on all activity LED power... OK
FAN_SET mode... OK
Turn off all status LED... OK
Turn on disk power... OK
=>

On entend bien les disques SATA démarrer, on peut taper boot, et la machine démarre correctement, puisque le noyau est capable de détecter les disques-durs.

Automatisation

Exécuter une opération manuelle à chaque démarrage n’est pas très pratique, surtout en cas de re-démarrage imprévu. Comme l’opération est simple, on va utiliser un microcontrôleur.

Il faut les spécifications suivantes :

Arduino

Par habitude, l’environnement de développement Arduino est pratique pour des prototypes simples, et la variante hardware Pro Mini3 est compacte et s’alimente en 3.3V.

Arduino Pro Mini FTDI

Je rencontre quelques soucis : il m’est impossible de faire fonctionner l’UART correctement à 115200 bit/s, puisque les cartes alimentées en 3.3V ont un quartz à 8MHz, et des diviseurs d’horloge qui ne permettent pas à l’UART de fonctionner à la bonne fréquence4.

J’avais commencé par suspecter les bibliothèques Arduino, avant d’utiliser le MCU bare-metal. Le code est plus long à écrire, mais l’exécution est plus rapide et on contrôle précisément ce que l’on fait. Comme mon problème d’UART était matériel, il n’a pas été résolu.

MSP430

J’ai une carte d’évaluation de MSP430 et un MSP430G2553 en stock, qui correspondent aux besoins5, avec l’intérêt supplémentaire d’avoir un oscillateur interne assez précis pour qu’aucun quartz ne soit nécessaire.

Energia

Energia est un port d’Arduino pour MSP430, qui permet de prototyper rapidement6.

L’intérêt est surtout de fournir une chaîne de développement quand les paquets ne sont plus présents dans Debian depuis 20197.

Pour utiliser la chaîne de développement sans l’IDE, il suffit d’adapter la commande suivante à l’endroit où les fichiers de Energia sont présents :

export PATH=$PATH:/opt/energia-1.8.10E23/hardware/tools/msp430/bin/

Le fonctionnement de Energia est correct, mais j’ai rencontré le même problème qu’avec le bibliothèques Arduino : le fichier exécutable est volumineux, et son exécution est lente. Ça fait une bonne excuse pour utiliser le MCU bare-metal.

Code

Le programme est construit avec deux machines d’état, et la réception des caractères se fait par interruptions.

On utilise un scheduler minimaliste8, où une interruption de timer va exécuter ce scheduler à 1kHz, qui va utiliser des variables (milliseconds et seconds) pour exécuter d’autres tâches. Ça permet de désactiver le CPU hors des interruptions, pour consommer moins d’énergie9.

__attribute__ ((interrupt(TIMER0_A0_VECTOR))) void timer_A_ISR(void) {
    milliseconds++;
    if(!(milliseconds % 1000)) {
        seconds++;
    }
    if(!(milliseconds % DELAY_FSM)) {
        fsm();                  // 100 Hz
    }
}

On utilise une machine à 4 états pour recevoir les commandes et envoyer les commandes correspondantes.

FSM
void fsm() {
    /*
    * 0: default, listening for 1st string
    * 1: 1st string matched, waiting 100ms, sending '^C'
    * 2: listening for 2nd string
    * 3: 2nd string matched, waiting 100ms, sending "boot\n"
    */
    static unsigned long delay = 0;
    switch(state) {
        case 1:
            if(delay == 0)
                delay = milliseconds;
            if(milliseconds - delay >= 100) {
                putchar(0x03);      // ^C
                delay = 0;
                state = 2;
                //toggle_LED();
            }
            break;
        case 2:
            listening_cond(str2);
            break;
        case 3:
            if(delay == 0)
                delay = milliseconds;
            if(milliseconds - delay >= 100) {
                puts("boot\n");
                delay = 0;
                state = 0;
                clearbuf();
                //toggle_LED2();
            }
            break;
        default:
            listening_cond(str1);
            break;
    }
}

Les LEDs permettent de surveiller l’exécution lorsqu’on va tester la carte en conditions réelles, avec le debugger débranché.

Gestion de l’UART

La pratique par défaut est de stocker les caractères reçus dans un buffer circulaire10. Ensuite, on peut les extraire dans un buffer linéaire pour le comparer avec les chaînes de caractères de référence.

Ring buffer

Ça fonctionne, mais ça utilise beaucoup de mémoire, et le parcours puis la copie du buffer sont lents. Il faut augmenter la taille du buffer pour ne pas rater de caractère, ce qui utilise encore plus de mémoire.

On va plutôt utiliser un buffer linéaire glissant, qui sont habituellement utilisés pour des opérations de filtrage. Le glissement du tableau se fait sur lui-même, et on peut comparer directement ce buffer avec les chaînes de caractères de référence.

Conditions réelles

Une fois les fonctions unitaires et le système validés, on peut brancher la carte d’évaluation au NAS.

Une fois l’alimentation du NAS branchée, les LEDs de la carte d’évaluation s’allument, et les disques durs du NAS se mettent à tourner.

Il ne reste plus qu’à câbler tout ça sur un morceau de plaque à trous.

Hacked board

Le code source est disponible11 sous license CC BY-NC.

Références


  1. Nuuo NVRmini - Monorailc.at↩︎

  2. Kernel Panic - Wikipedia↩︎

  3. Arduino Pro Mini - Arduino Documentation↩︎

  4. ATMega328P - Datasheet, section 19.11↩︎

  5. MSP430F2xx, MSP430G2xx Family User’s Guide (Rev. K), MSP430G2553 - Datasheet↩︎

  6. Energia↩︎

  7. Package: gcc-msp430 - Debian sources↩︎

  8. Il n’y a pas de drapeau pour forcer une exécution séquentielle, il faut s’assurer que les tâches se terminent assez vite et ne bloquent pas↩︎

  9. La consommation théorique est de 4mA en mode Active à 16MHz et 3.3V, et <1uA en mode LPM3, heureusement que l’alimentation du NAS est capable de fournir 100W↩︎

  10. Circular Buffer - Wikipedia↩︎

  11. Code source CC BY-NC↩︎

Electronics Électronique puissance semiconducteur semiconductors power Hardware CPE INSA Xavier Bourgeois

Xavier