samedi 17 janvier 2015

questions quiz

Voici un petit programme à tester dans le simulateur de MPLABX en mode pas à pas. Mais avant essayez de deviner le contenu de STATUS après chaque opération suivie du commentaire STATUS=?. Si vous répondez correctement à chaque étape votre compréhension du fonctionnement interne du CPU est excellente.


    include p10f200.inc
    __config _WDTE_OFF
    radix dec
    org 0
main_loop
    bsf STATUS,0   ; set C bit
    bsf STATUS,1   ; set DC bit
    bsf STATUS,2   ; set Z bit
    clrf STATUS    ; Q1, STATUS=?
    bsf STATUS,7   ; Q2, STATUS=?
    movfw STATUS   ; Q3, STATUS=? W=?
    movlw 0x78
    addwf STATUS,F ; Q4, STATUS=?
    movfw STATUS   ; Q5, STATUS=? W=?
    xorwf STATUS,F ; Q6, STATUS=?
    goto main_loop
    end
Pour vous aidez dans votre réflexion voici une représentation du registre STATUS des PIC10F20X.

Réponses et explications

  1. STATUS=0x1F. Pensiez-vous que le contenu de STATUS serais mis à zéro? Erreur car certains bits sont en lecture seule : ~TO et ~PD. De plus Z est mis à 1 car l'instruction CLRF affecte ce bit en le mettant à 1. L'ajustement des bits Z,DC et C se fait à la fin de l'opération et l'opération CLRF ne change pas l'état des indicateurs DC et C. Ces deux là était à 1 donc ils le reste. Donc si vous voulez mettre à zéro les 3 indicateurs ne faites pas un CLRF STATUS mais plutôt:
    
      BCF STATUS,Z
      BCF STATUS,DC
      BCF STATUS,C
    
  2. STATUS=0x9F. Ce bit est R/W donc il es mis à 1 tel que prévu par l'opération. Les autres bits ne sont pas affectés.
  3. STATUS=0x9B et W=0x9F. C'est normal puisque l'instruction MOVFW affecte la valeur de l'indicateur Z. Celui-ci a été mis à zéro puisque la valeur transféré dans W n'était pas nulle.
  4. STATUS=0x1B. L'addition a bien donnée le résultat escomptée sauf que les indicateurs Z, DC et C ont été ajusté en conséquence de l'addition. Comme toujours les bit en lecture seule de STATUS n'ont pas été modifiés par le résultat et les 3 indicateurs ont écrasés les bit 0-2 du résultat. Si vous voulez vérifier que l'addition donne le résultat escompté remplacé addwf STATUS, F par addwf STATUS, W et vérifier le résultat dans W.
  5. STATUS=0x1B et W=0x1B. Cette fois-ci STATUS n'a pas été modifié par l'opération MOVFW puisque Z était déjà à zéro.
  6. STATUS=0x1F. l'opération XORWF n'affecte que le bit Z. Ici on a fait une opération xor de la valeur de STATUS avec elle-même. Le résultat d'une telle opération est zéro. Donc le bit Z a été mis à 1. les bits DC et C ne sont pas altérés. Encore une fois les 3 indicateurs écrase les bits 0-2 du résultat. Le bit 4 (~PD) était à 1 et le reste puisqu'il est en lecture seule.

jeudi 15 janvier 2015

PIC micro Pascal, test #2

J'ai poursuivi mes expérimentations avec PMP. Cette fois ci j'ai repris le programme ambiance pingpong et j'ai retravaillé les versions assembleur et XC8 et créé une version avec PMP. Ces versions cible le PIC10F200 au lieu du PIC10F202, ce qui réduit la mémoire programme à un maigre 256 location et la RAM à 16 octets. J'ai commencé par la version en 'C' et j'ai vraiment du me creuser les méninges pour que ça rentre dans les 16 octets de RAM car le compilateur XC8 utilise plusieurs octets de RAM supplémentaires en plus de celle définis dans le code source. J'ai finalement réussi à faire entrer ça dans les 16 octets de RAM. Pour la mémoire FLASH il n'y a pas vraiment eu de problème. Dans cet article je présente donc les 3 versions de code, et je compare les ressources utilisées ainsi que la vitesse d'exécution.

Méthode de travail améliorée

Finalement j'ai découverts la méthode la plus pratique pour travailler avec PMP en utilisant MPLABX pour la programmation du MCU. Dans MPLABX je crée un projet et j'importe le fichier assembleur généré par PMP. Chaque fois que PMP recompile le nouveau fichier assembleur ce dernier est automatiquement disponible dans le projet MPLABX et je n'ai qu'à cliquer sur le bouton "Make and program device" dans la barre d'outil de MPLABX pour reprogrammer le MCU. C'est en fait plus simple que d'utiliser le programme PICKIT 2 programmer et ce n'est pas limité au MCU supportés par le PICKIT 2.

Comparaison des ressources

Voici un tableau comparatif des ressources utilisées par chaque version du programme. Boucle/min. est le nombre de fois que la boucle principale du programme s'exécute pendant la minute d'activité. Sans surprise le code assembleur est beaucoup plus rapide.

versionassembleurC (XC8 free)PIC micro Pascal
RAM111615
FLASH101164162
boucles/min.901560005000

Il semble que les résultats pour XC8 et PMP soient très semblable mais en fait le code assembleur généré par PMP serais de 150 instructions et la RAM utilisée serait de 14 octets si ce n'était pas d'un bug dans la version 2.0.6B du compilateur. le code original de transition était: Lorsque le bug sera corrigé dans la version finale de PMP 2.0.6 cette version pourra être utilisée. Pour le moment lorsqu'on passe l'élément d'un tableau aux procédures inc() et dec() c'est toujours le premier élément qui est modifié.

Vitesse d'exécution

Si on regarde le code source, on se rends compte que le gros du temps processeur est passé dans la procédure pwm_control. donc plus cette procédure est courte plus la boucle PWM sera rapide. Pour la version écrite en assembleur cette procédure utilise 17 instructions, celle en C est de 28 instructions et finalement pour celle écrite en Pascal est de 32 instructions. Donc même si au total PMP génère un code légèrement plus court que XC8 ce n'est pas le cas pour la procédure pwm_control ce qui explique qu'en terme de vitesse d'exécution ce code est le plus lent des 3.

Code source des 3 version

La constante EXPIRE est choisie en fonction de la vitesse d'exécution de chaque version pour une durée d'activité de 60 secondes. En première approximation EXPIRE = 60/PWM_PERIOD. La période PWM est elle-même en première approximation


PWM_PERIOD= 256*N*Tcy
Tcy = 1µsec
N ~=nombre d'instructions dans la routine pwm_control+
    nombre d'instructions supplémentaires dans la boucle
    lorsque pwm_cntr<>0.
Pour chaque version j'ai chronométrée la durée d'activité et recalculé la valeur de EXPIRE et chronométré à nouveau avec la valeur calculée pour m'assurer d'une activité de 60 secondes.

Code source version assembleur

Code source version C

Code source version Pascal

lundi 12 janvier 2015

PIC micro Pascal

La semaine dernière j'ai découvers l’existence d'un compilateur PASCAL pour les microcontrôleurs PIC 8 bits. Ce compilateur s'appelle PIC micro Pascal ou en abrégé PMP. Lorsque je programme des MCU je le fais en assembleur ou en 'C'. Mais comme j'ai programmé en Turbo Pascal et en Delphi par le passé j'ai décidé de mettre ce compilateur au banc d'essai. Pour ce faire j'ai utilisé la version 2.06 qui est encore en version bêta. J'ai d'ailleurs découvers et rapporté un bug régressif1 dans cette version. Je reparlerai de ce bug plus loin dans cet article.

Présentation

L'initiateur et auteur principal de PMP est Philippe Paternotte, la contribution des autres membres de l'équipe consiste principalement en des librairies. Il a écris ce compilateur en Delphi, il s'agit d'une application Windows. PMP est disponible gratuitement mais le code source ne l'est cependant pas. Il ne s'agit pas simplement d'un compilateur mais aussi d'un IDE basé sur Scintilla.

PMP est un sous-ensemble de Turbo Pascal, les principales restrictions étant les suivantes.

  • Ne supporte pas la programmation par objets.
  • Les ARRAY ne peuvent avoir qu'une seule dimension.
  • Ne supporte pas les fonctions et procédures imbriquées.
  • Ne supporte que les RECORD simple, i.e. sans RECORD imbriqués, ni ARRAY ou CASE.
  • Ne supporte qu'un seul niveau d'indirection, i.e. v1^m1^x n'est pas supporté.

PMP ne génère pas de code binaire pour les PIC il génère plutôt un fichier source pour l'assembleur MPASM. Donc MPLAB ou MPLABX doit-être installé avant de procéder à l'installation de PMP. Lors de l'installation PMP recherche mpasm.exe et mplink.exe et doit les trouvés pour fonctionner correctement.

Puisque PMP n'est pas intégré à MPLAB(X), pour flasher le microcontrôleur il faut soit utiliser un outil externe comme Pickit 2 programmer ou ce qui est plus malcommode créer un projet dans MPLAB(X) et y importer le fichier source assembleur généré par PMP. Une autre possibilité est d'utiliser les outils GPUTILS. Dans sa version 2.06 PMP supporte les outils GPUTILS. Pour utiliser GPUTILS sous windows il faut installer mingw32.

En ce qui concerne la documentation qui viens avec PMP elle existe sous forme de fichier PDF et d'un fichier d'aide Windows CHM pour l'aide en ligne.

Installation

L'installation est si simple qu'elle se passe d'explications. Au premier lancement l'IDE demande si on veut associé les fichiers avec l'extension .pmp et .pas avec celle-ci. Sous Windows 7 l'installation se fait dans C:\Program Files (x86)\PMP\V2.0.6. Ce dossier contient un dossier examples.

Premier programme

Mon objectif principal pour ce banc d'essai était de voir si PMP fait une bonne optimisation du code. Dans ce but j'ai réécris le code de mon article intitulé chandelle électronique. J'ai recréé exactement la même structure de programme en Pascal que celle que j'avais en assembleur.

Ce programme utilise un PIC10F202. Ce MCU n'est pas du tout conçu pour supporter la programmation dans un langage de haut niveau comme PASCAL, ce qui rend l'optimisation encore plus difficile. Voici donc le code source créé dans l'IDE de PMP. Le compilateur génère le fichier .asm suivant. version C compilée avec XC8 free.

Comparaison

usageASMPMPXC8 free
octets RAM91218
code FLASH779094
Les octets de RAM supplémentaires utilisés par PMP sont:
  • __BitStack, 1 octet, sert à sauvegarder les status bits pour la donnée qui est dans __STACK__0.
  • __STACK__0, 1 octet, utilisé comme variable temporaire.
  • __FLAGS, 1 octet, est utilisé pour les variables de type boolean définies dans le programme PASCAL.
La variable __FLAGS n'est pas utilisée puisqu'il n'y a pas de variable booléennes dans le programme. LED ne compte pas car cette variable est définie sur le SFR GPIO. Notez qu'on utilise @ pour définir une variable sur une adresse absolue. donc dans le code

var
  LED :boolean @ GPIO.2 ;
Signifie que la LED est sur le BIT 2 du SFR GPIO. Ce qui en assembleur est traduis par:

flicker.LED     equ     2        flicker.LED       ; Bit 2 in GPIO
Puisque __FLAGS n'est pas utilisée dans ce programme le compilateur aurait du optimiser en supprimant cette variable ainsi que l'instruction clrf __FLAGS dans la section d'initialisation.

Bug régressif dans la version 2.06B

A la ligne 49 du code PASCAL on retrouve la ligne:


if (7<rand_val) then rand_val:= rand_val div 2;
Ce n'est pas le code que j'ai écris au départ mais plutôt:

if (rand_val>7) then rand_val:= rand_val div 2;
Mais pour faire la comparaison le compilateur a généré:

        movf    flicker.rand_val, W     ; Get variable in acc
        bsf     __BitStack, 0           ; Prepare bit ACC (true)
        sublw   h'07'                   ; subtract W to constant
Le problème c'est que l'instruction sublw n'existe pas dans le jeux d'instructions des PIC baseline. Mais simplement en inversant la comparaison le code généré deviens:

        movlw   h'07'
        movwf   __STACK__0              ; Push byte
        movf    flicker.rand_val, W     ; Get variable in acc
        bsf     __BitStack, 0           ; Prepare bit ACC (true)
        subwf   __STACK__0, W           ; Compare to stack byte

Lorsqu'on étudie le code assembleur généré par PMP on comprends rapidement pourquoi ça prend 16% de plus d'instructions. Il semble que toutes les comparaisons sur les variables passe par __BitStack et __STACK__0.

Conclusion

Bien sur ce banc d'essai est bref et je vais certainement poursuivre d'autres expérimentations avec PMP mais ça m'a quand même permis de me faire une idée du prix a payer en terme d'utilisation de l'espace de code. Le résultat est meilleur que celui obtenu avec XC8 version gratuite. Donc pour ceux qui préfère le PASCAL au 'C' ça peut-être intéresssant. Personnellement pour un programme PIC qui a moins de 512 instructions je préfèrerai toujours programmer en assembleur. Donc pour tous les PIC10F, PIC12F qui disposent de 256/512 instructions de FLASH.


NOTES:
1) un bug régressif est un bug qui a été introduit dans la version courante alors que la même fonctionnalité fonctionnait correctement dans une version antérieure.