PDA

Voir la version complète : [NDS][Tutorial] Programmer sur DS avec la libnds


Pitt
11/03/2007, 21h23
Programmer sur DS avec la libnds
Version 20070427
par Pitt





## Partie A, Théorie


>> Sommaire



0. Introduction

1. Console, texte

2. Le hardware de la DS

2.1 Présentation
2.2 Connexion sans fil
2.3 Contrôles/sorties
2.4 Mémoire


3. Touches, pad et stylet

3.1 Touches et pad
3.2 Stylet


4. Vidéo 2D

4.1 "Power management"


5. Vidéo 3D

6. Direct Memory Access

7. Timers

8. Interruptions

8.1 Interruptions hardwares
8.2 Interruptions softwares


9. Inter Processor Communication (IPC)

10. Mots de la fin

10.1 Remerciements
10.2 Liens




0. Introduction

Ce tutoriel s'adresse à tous ceux qui souhaitent se lancer dans la programmation sur DS à l'aide, ou pas, de la libnds. Il vise plus à servir de référence qu'à initier, donc une expérience en programmation sur GBA, ou sur DS avec la PAlib constitue un atout non négligeable pour en débuter la lecture. J'essayerai d'être le plus court et concis possible, tout en restant relativement précis.

Comme son nom ne l'indique pas, ce tutoriel n'est pas destiné qu'à ceux qui veulent utiliser la libnds : j'essayerai d'ajouter le plus possible les adresses des registres et les différentes constantes et autres bits, pour permettre à ceux qui voudraient se débrouiller seuls ou seulement comprendre un peu mieux le hardware DS, d'avoir une documentation relativement précise et pas trop barbante ...

Pour le moment, ce tutoriel n'explique pas comment installer devkitpro et libnds, mais c'est tellement simple, et il y a suffisamment de bons tutoriels à ce sujet sur PA et sur le web pour que j'évite de le faire. Une fois ce document terminé, je le rajouterai peut-être, mais pas avant que j'aie mis toutes les choses utiles. Au cas où, vous avez les liens à la fin du tutoriel.

Bonne lecture !


N.B.: Sauf indication contraire, vous pouvez utiliser le template arm9 des exemples de la libnds pour tester les notions abordées dans ce tutoriel.


1. Console, texte

Avant d'entrer dans les détails techniques, il peut être sympathique d'aborder de façon simple le développement sur DS. Cette première partie montre donc brièvement comment afficher du texte grâce à une console par défaut, initialisée par la libnds.

Certaines notions peuvent vous être complètement inconnues, surtout si vous n'avez jamais programmé sur GBA. Mais le but de cette première partie est justement d'afficher un petit quelque chose, pour le plaisir de ceux qui débutent.
Vous pourrez donc revenir à cette partie plus tard, notamment après avoir lu la partie "Vidéo 2D" de ce tutoriel, pour mieux comprendre le pourquoi du comment.

Voici donc un petit Hello world commenté, qui vous permettra d'afficher du texte, même sans vraiment comprendre comment cela fonctionne réellement :


#include <nds.h>
#include <stdio.h>

int main(void)
{
/**
* Il n'est pas nécessaire de comprendre cette première partie,
* sauf si vous avez déjà lu le tutoriel en son ensemble.
* Donc débutant, passez directement à la case 7.
*/

/* 1) Initialisation des interruptions */

irqInit();
irqSet(IRQ_VBLANK, 0);

/* 2) On initialise l'écran supérieur, mais pas
* le tactile, étant donné qu'il nous est inutile. */

videoSetMode(0);
videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE);

/* 3) On active la bonne banque de données sur notre écran */

vramSetBankC(VRAM_C_SUB_BG);

/* 4) On configure l'adresse de la carte de notre fond */

SUB_BG0_CR = BG_MAP_BASE(31);

/* 5) La couleur du texte correspond à la couleur 255
* de la palette ; on utilise la macro RGB() */

BG_PALETTE_SUB[255] = RGB15(31, 31, 31);

/* 6) On initialise notre console */

consoleInitDefault((u16 *) SCREEN_BASE_BLOCK_SUB(31), (u16 *) CHAR_BASE_BLOCK_SUB(0), 16);

/* 7) On affiche du texte avec la fonction iprintf,
* qui prend comme unique argument le texte à afficher */

iprintf("Hello world !\n");

/* 8) Une boucle infinie, pour éviter de freezer,
* ça serait dommage ... */
while (1);

return 0;
}


Cette première partie n'est finalement qu'un aperçu pour les plus pressés, et elle n'apprend pas grand chose ... La troisième partie traite des différentes entrées basiques de la DS. Mais avant cela, il faut bien parler du hardware de la DS.


2. Le hardware de la DS

2.1 Présentation

La Nintendo Dual Screen, ou DS, est une console portable. Je précise au cas où vous ne seriez pas au courant ... Développée par Nintendo, elle est dotée de 2 processeurs, de la même famille, un ARM946E-S, cadencé à 67 MHz, et un ARM7TDMI, cadencé à 33 MHz. Pour le moment, nous n'utiliserons "que" l'ARM9, pour la simple et bonne raison que c'est celui qui nous permet d'utiliser les fonctions principales de la DS. Mais par la suite, nous utiliserons le second processeur.

2.2 Connexion sans fil

La DS gère la communication sans fil de 2 manières : en utilisant la norme IEEE 802.11 pour la connexion à internet, et un format propriétaire Nintendo, le NiFi, pour communiquer entre DS.
La première méthode peut être gérée via la libwifi, mais il n'y a encore aucune librairie fonctionnelle permettant d'utiliser le NiFi.

2.3 Contrôles/sorties

La DS est dotée de 2 écrans, dont un tactile. Ils ont tous les deux une résolution de 256x192 pixels, un pitch de 0,24 mm et ils gèrent 262 000 couleurs.
En plus de l'écran tactile, la DS possède de nombreux contrôles : une croix multidirectionnelle, et 8 boutons X, Y, A, B, L, R, Start et Select. Elle dispose également d'un micro intégré, en dessous de l'écran tactile pour les DS, et entre les deux écrans pour la DS Lite.
Enfin, elle dispose de 2 haut-parleurs stéréo.

2.4 Mémoire

La DS est dotée de 4 Mo de mémoire RAM. De plus, l'ARM7 peut accéder à une mémoire de 64 ko, et la console possède également une zone de mémoire partagée par l'ARM9 et l'ARM7, de 32 ko. Enfin, une mémoire de 656 ko est réservée à la vidéo, c'est-à-dire à l'unité graphique de la DS.
Le tableau suivant montre les types de données utilisés par la DS, et leurs equivalents utilisés par GCC :

Nom|Taille en bits
{colsp=2}Types génériques
Nibble|4
Octet (byte)|8
Demi-mot (halfword ou hword)|16
Mot (word)|32
Double-mot (doubleword ou dword)|64
{colsp=2}Types utilisés par GCC
char|8
short|16
long|32
long long|64
float|32
double|64


Voici également un tableau des différents types déclarés par la libnds :

Non-signé|Signé|Volatile non-signé|Volatile signé|Taille en bits|Abbréviations
bool|-|-|-|8|-
uint8|int8|vuint8|vint8|8|u8, s8, vu8, vs8
uint16|int16|vuint16|vint16|16|u16, s16, vu16, vs16
uint32|int32|vuint32|vint32|32|u32, s32, vu32, vs32
uint64|int64|vuint64|vint64|64|u64, s64, vu64, vs64
-|float32|-|vfloat32|32|-
-|float64|-|vfloat64|64|-


De plus, la DS est Little Endian, donc les octets qui composent chaque mot sont inversés. Par exemple le double-mot 0xBADC0FEE sera stocké comme suit :

Octet|3|2|1|0
Valeur|BA|DC|OF|EE




3. Touches, pad et stylet

La gestion des touches, du pad et du stylet est extrêmement simple sur DS. Cette troisième partie passe rapidement en revue les registres, et les fonctions de la libnds, servant à l'utilisation des entrées de la DS, du moins au niveau des doigts ...

3.1 Touches et pad

La DS stocke l'état actuel des différentes touches dans le registre REG_KEYINPUT, registre 16 bits situé à l'adresse 0x04000130.

Bit|13|12|11|10|9|8|7|6|5|4|3|2|1|0
Nom|KEY_LID|KEY_TOUCH|KEY_Y|KEY_X|KEY_L|KEY_R|KEY_ DOWN|KEY_UP|KEY_LEFT|KEY_RIGHT|KEY_START|KEY_SELEC T|KEY_B|KEY_A
Processeur|ARM7|ARM7|ARM7|ARM7|Les 2|Les 2|Les 2|Les 2|Les 2|Les 2|Les 2|Les 2|Les 2|Les 2
Représente|Diode|Ecran tactile|Bouton Y|Bouton X|Bouton L|Bouton R|Bas|Haut|Gauche|Droite|Start|Select|Bouton B|Bouton A


Il suffit donc de lire le contenu de ce registre, et d'utiliser des masques de bits pour détecter quelles touches sont pressées. Certains des bits ne sont actualisés que pour l'ARM7, mais cela importe peu quand on programme à l'aide de la libnds, car celle-ci fait passer le contenu de REG_KEYINPUT à l'ARM9 via l'IPC (voir plus loin).

La libnds propose plusieurs déclarations concernant la lecture des touches :


Une fonction permettant de récupérer le contenu du registre REG_KEYINPUT dans un buffer.

void scanKeys();


2 fonctions permettant de savoir, une fois le contenu de REG_KEYINPUT mis en buffer, quelles touches sont respectivement :
- maintenues appuyées
- pressées
- relevées
depuis le dernier appel à scanKeys().

uint32 keysHeld(void);
uint32 keysDown(void);
uint32 keysUp(void);


/!\ Si le joueur reste appuyé sur un bouton, keysDown() renverra 0 pour ce bouton. C'est alors keysHeld() qui prendra le relais.
il ne faut donc pas confondre ces 2 fonctions, et distinguer la différence entre une touche relevée, pressée ou maintenue.


2 fonctions permettant respectivement de détecter la répétition d'un appui sur une touche, et de paramètrer la répétition des touches.

uint32 keysDownRepeat(void);
/**
* setDelay est le nombre d'appels à scanKeys() avant que les touches commencent à se répéter.
* setRepeat est le nombre d'appels à scanKeys() avant que les touches ne se répètent.
*/
void keysSetRepeat( u8 setDelay, u8 setRepeat );


Une énumération représentant la valeur des différentes touches.

typedef enum KEYPAD_BITS {
/* Touches */
KEY_A = BIT(0),
KEY_B = BIT(1),
KEY_SELECT = BIT(2),
KEY_START = BIT(3),
KEY_RIGHT = BIT(4),
KEY_LEFT = BIT(5),
KEY_UP = BIT(6),
KEY_DOWN = BIT(7),
KEY_R = BIT(8),
KEY_L = BIT(9),
KEY_X = BIT(10),
KEY_Y = BIT(11),
/* Ecran tactile */
KEY_TOUCH = BIT(12),
/* Etat de la diode */
KEY_LID = BIT(13)
} KEYPAD_BITS;



Un usage fréquent de ces fonctions est présenté ci-dessous :

scanKeys();
if (keysDown() & KEY_A)
{
/* si le bouton A est pressé ...*/
}


3.2 Stylet

Pour savoir si le stylet est appuyé sur l'écran, il suffit d'effectuer un scanKeys(), puis de tester keysDown() avec le masque de bit KEY_TOUCH.
Pour connaitre l'endroit où le stylet est appuyé, il faut utiliser la fonction suivante, qui retourne une structure touchPosition. Cette structure contient 6 champs, qui sont expliqué plus bas.


touchPosition touchReadXY();



/* La structure touchPosition */
typedef struct touchPosition {
int16 x; /* Coordonnée X de l'endroit où l'écran est touché */
int16 y; /* Coordonnée Y de l'endroit où l'écran est touché */
int16 px; /* Coordonnée X du pixel à l'endroit où l'écran est touché */
int16 py; /* Coordonnée Y du pixel à l'endroit où l'écran est touché */
int16 z1; /* FIXME : profondeur de l'appui ? */
int16 z2; /* FIXME : profondeur de l'appui ? */
} touchPosition;


Cette structure est passée à l'ARM9 par l'ARM7 via une zone commune aux 2 processeurs, qui permet d'échanger des informations entre eux, l'IPC. Cette zone est expliquée plus en détail dans la partie 9, et ce sera par ailleurs l'occasion d'expliquer plus en détail les registres qui concernent la récupération des coordonnées du stylet, de la pression des touches X et Y, et de l'écran tactile.


4. Vidéo 2D

La DS est dotée d'un hardware relativement bien fourni concernant la 2D : il existe de multiples façons d'accéder aux écrans, et d'y afficher ce que l'on désire.
Il faudra bien comprendre dans cet partie la différence entre l'écran principal, généralement (mais pas tout le temps) utilisé en bas, et l'écran secondaire. Pourquoi cette distinction ? Parce qu'on peut échanger la place des 2 écrans, ce qui peut fausser toutes vos fonctions d'affichage si vous n'y pensez pas. De plus, la section suivante s'intéresse au hardware 3D, qui n'est utilisable QUE sur l'écran principal.


4.1 "Power management"

Tout d'abord, l'unité LCD est régie par un registre de gestion de l'alimentation, qui permet d'activer, ou non, les 2 écrans, mais aussi de déterminer quelles opérations sont activées.
C'est le registre 16bits REG_POWERCNT, situé à l'adresse 0x04000304.
Le tableau suivant récapitule les différents bits activables de REG_POWERCNT :

Bit|Define de la libnds|Action
0|POWER_LCD|Active les 2 écrans LCD
1|POWER_2D_A|Active la 2D sur l'écran principal
2|POWER_MATRIX|Active les matrices 3D
3|POWER_3D_CORE|Active la 3D sur l'écran principal
9|POWER_2D_B|Active la 2D sur l'écran secondaire
15|POWER_SWAP_LCDS|Echange les 2 écrans


Afin de simplifier la vie des codeurs, la libnds contient 2 macros supplémentaires :
- POWER_ALL_2D, qui active toute la 2D (écrans, 2D sur chaque écran)
- POWER_ALL, qui active tout (écrans, 2D sur chaque écran, 3D)

La libnds fournit plusieurs fonctions concernant le "power management" :


Une fonction qui ajoute les paramètres qu'on lui donne

static inline void powerON(int on);

Une fonction qui n'active QUE les paramètres qu'on lui donne

static inline void powerSET(int on);

Une fonction qui désactive les paramètres qu'on lui donne

static inline void powerOFF(int off);

3 fonctions de gestion de la position des écrans


/* - Echange les 2 écrans */
static inline void lcdSwap(void);
/* - Mettre l'écran principal en haut */
static inline void lcdMainOnTop(void);
/* - Mettre l'écran principal en bas */
static inline void lcdMainOnBottom(void);




Deux utilisations typiques sont présentées ci-dessous :


/* - utilisation de la 2D uniquement */
powerON(POWER_ALL_2D);
/* - utilisation de la 2D et de la 3D */
powerON(POWER_ALL);



5. Vidéo 3D


6. Direct Memory Access

Pour transférer de manière rapide, on peut utiliser une technique spéciale, appelée Direct Memory Access, ou DMA. Comme son nom ne l'indique qu'à moitié, cette méthode demande au processeur de stopper l'exécution du programme et de transférer directement des données en mémoire. Cela peut avoir des avantages considérables, surtout lors de l'utilisation de modes graphiques bitmaps, ou encore pour transférer des sons vers les hauts-parleurs. Mais en contre partie, le DMA stoppe l'exécution du processeur, ce qui peut être vu comme un inconvénient.

La DS possède 4 canaux de transfert DMA, qui sont utilisables grâce aux registres DMA_CR(x), DMA_SRC(x) et DMA_DEST(x), où x est le numéro de canal compris entre 0 et 3. C'est 4 canaux ne diffèrent que par l'usage qu'on leur réserve généralement :
- canal 0 : le plus rapide, surtout utilisé pour les transferts critiques.
- canaux 1 et 2 : utilisés pour le transfert du son.
- canal 3 : les autres transferts.
Ces indications sont bien entendues théoriques ; le canal 0 peut très bien être utilisé pour transfèrer du son, et on peut très bien copier une structure avec le canal 1.

Le premier registre, DMA_CR(x), permet le contrôle du transfert DMA ; le tableau suivant récapitule les paramètres qui peuvent être utilisés pour le contrôle d'un transfert, via le registre DMA_CR(x) qui est un registre 32 bits situé à l'adresse :
- 0x040000B0 pour le canal 0.
- 0x040000BC pour le canal 1.
- 0x040000C8 pour le canal 2.
- 0x040000D4 pour le canal 3.

Paramètre|Bit|Processeur|Action
{colsp=2}Activation du transfert
DMA_ENABLE|31|ARM7 & ARM9|Active le transfert DMA sur ce canal.
DMA_IRQ_REQ|30|ARM7 & ARM9|Active la génération d'une interruption à la fin du transfert.
DMA_START_NOW|-|ARM7 & ARM9|Commence le transfert DMA immédiatement.
DMA_START_CARD|-|ARM7 & ARM9|
DMA_START_VBL|27|ARM7 & ARM9|Commence le transfert DMA au prochain VBL.
DMA_START_HBL|28|ARM9|Commence le transfert DMA au prochain HBL.
DMA_START_FIFO|-|ARM9|
DMA_DISP_FIFO|-|ARM9|
{colsp=2}Tailles de transfert
DMA_16_BIT|-|ARM7 & ARM9|Transfert de demi-mots (halfwords = 16 bits).
DMA_32_BIT|26|ARM7 & ARM9|Transfert de mots (words = 32 bits).
{colsp=2}Types de transfert
DMA_REPEAT|25|ARM7 & ARM9|
DMA_SRC_INC|-|ARM7 & ARM9|Récupère les données à copier de manière ascendante.
DMA_SRC_DEC|23|ARM7 & ARM9|Récupère les données à copier de manière descendante.
DMA_SRC_FIX|24|ARM7 & ARM9|Copie toujours le même demi-mot/mot.
DMA_DST_INC|-|ARM7 & ARM9|Copie les données de manière ascendante.
DMA_DST_DEC|21|ARM7 & ARM9|Copie les données de manière descendante.
DMA_DST_FIX|22|ARM7 & ARM9|Copie toujours au même endroit.
DMA_DST_RESET|-|ARM7 & ARM9|
{colsp=2}Transferts prédéfinis
DMA_COPY_WORDS|-|Transfert immédiat de mots.
DMA_COPY_HALFWORDS|-|Transfert immédiat de demi-mots.
DMA_FIFO|-|


Le bit 31 (= DMA_BUSY) du registre DMA_CR(x) indique, une fois le transfert commencé, si le canal est occupé ou non. La libnds fournit également la fonction qui suit, et qui permet de savoir si le canal DMA choisi est libre, ou pas :


static inline int dmaBusy(uint8 channel);


Le second registre, DMA_SRC(x), contient l'adresse des données à copier.
C'est également un registre 32 bits, situé à l'adresse :
- 0x040000B4 pour le canal 0.
- 0x040000C0 pour le canal 1.
- 0x040000CC pour le canal 2.
- 0x040000D8 pour le canal 3.

Le troisième registre, DMA_DEST(x), contient l'adresse à laquelle les données seront transférées.
Celui-ci est encore une fois un registre 32 bits, situé à l'adresse :
- 0x040000B8 pour le canal 0.
- 0x040000C4 pour le canal 1.
- 0x040000D0 pour le canal 2.
- 0x040000DC pour le canal 3.

La libnds fournit plusieurs fonctions de transferts prédéfinies :


Transferts synchrones


/* - de mots */
static inline dmaCopyWords(uint8 channel, const void* src, void* dest, uint32 size);
/* - de demi-mots */
static inline void dmaCopyHalfWords(uint8 channel, const void* src, void* dest, uint32 size);


Transferts Asynchrones


/* - de mots */
static inline void dmaCopyWordsAsynch(uint8 channel, const void* src, void* dest, uint32 size);
/* - de demi-mots */
static inline void dmaCopyHalfWordsAsynch(uint8 channel, const void* src, void* dest, uint32 size);


Transferts "à la memcopy", utilisant le canal 3


/* - synchrone */
static inline void dmaCopy(const void * source, void * dest, uint32 size);
/* - asynchrone */
static inline void dmaCopyAsynch(const void * source, void * dest, uint32 size);



Sinon, une utilisation typique du DMA se déroule comme suit :


/* Version synchrone */
DMA_SRC(canal) = adresse_source;
DMA_DEST(canal) = adresse_destination;
DMA_CR(canal) = parametres | taille;
while (dmaBusy(canal));

/* Version asynchrone */
DMA_SRC(canal) = adresse_source;
DMA_DEST(canal) = adresse_destination;
DMA_CR(canal) = parametres | taille;



7. Timers

Un timer est un registre compteur, qui joue le rôle d'horloge. Il permet par exemple d'attendre un certain temps, ou d'effectuer une action à intervalles réguliers. La DS possède 4 timers, numérotés de 0 à 3, qui sont tous les quatre cadencés à 33.514 MHz. L'utilisation de ces derniers est très simple, et s'effectue grâce à 2 registres.

Le premier, TIMER_CR(x), où x est le numéro du timer, permet de gérer, comme pour les transferts DMA, la configuration et la mise en place du timer. Le tableau qui suit montre les différents paramètres que l'on peut sélectionner. Le registre TIMER_CR(x) est un registre 16 bits, qui se situe à l'adresse :
- 0x04000102 pour le timer 0.
- 0x04000106 pour le timer 1.
- 0x0400010A pour le timer 2.
- 0x0400010E pour le timer 3.

Paramètre|Bit|Action
TIMER_ENABLE|7|Active le timer.
TIMER_IRQ_REQ|6|Active la génération d'une interruption lors du débordement du timer.
TIMER_CASCADE|2|Active la mise en cascade des timers, c'est-à-dire que le timer ne s'active que lorsque le timer précédent déborde. Ne peut être utilisé sur le timer 0.
TIMER_DIV_1|0-1|Cadence le timer à 33.514 MHz.
TIMER_DIV_64|0-1|Cadence le timer à (33.514 / 64) MHz.
TIMER_DIV_256|0-1|Cadence le timer à (33.514 / 256) MHz.
TIMER_DIV_1024|0-1|Cadence le timer à (33.514 / 1024) MHz.


Le second registre, TIMER_DATA(x) possède un comportement un peu plus compliqué. En effet, il permet en écriture de sélectionner la fréquence du compteur, grâce aux macros présentées dans le tableau suivant, qui sont utilisées suivant la division de la cadence du timer. Mais en lecture, il renvoit la valeur actuelle du compteur.
Ce registre de 16 bits se situe à l'adresse :
- 0x04000100 pour le timer 0.
- 0x04000104 pour le timer 1.
- 0x04000108 pour le timer 2.
- 0x0400010C pour le timer 3.

Paramètre de division du timer|Macro pour le choix de la fréquence x
TIMER_DIV_1|TIMER_FREQ(x)
TIMER_DIV_64|TIMER_FREQ_64(x)
TIMER_DIV_256|TIMER_FREQ_256(x)
TIMER_DIV_1024|TIMER_FREQ_1024(x)


La libnds ne fournit aucune fonction de gestion de timers, mais leur utilisation est très simple, et ce fait comme suit :


/* En utilisant la bonne macro pour calculer la fréquence */
TIMER_CR(numero) = parametres;
TIMER_DATA(numero) = frequence;



8. Interruptions

8.1 Interruptions hardwares

Le processeur ARM9 utilisé jusqu'ici, tout comme l'ARM 7 d'ailleurs, lit les instructions du programme courant les unes après les autres, et les exécute. Il est relié à différents périphériques, comme par exemple les touches ou les hauts-parleurs.
Pour échanger des informations entre les périphériques, on peut utiliser 2 méthodes :

- la première, appelée polling consiste à attendre dans une boucle infinie qu'une condition soit remplie, comme par exemple la pression du bouton R. Cette méthode a ses avantages, mais aussi ses inconvénients, vus qu'on ne peut pas vraiment effectuer de longues tâches pendant la période d'attente.

- la seconde consiste à utiliser un système d'interruptions. Une interruption, au sens électronique du terme, est un simple fil, qui relie un périphérique au processeur. Cet entrée conserve toujours la même valeur, soit 0 ou 1. Mais lorsque le périphérique a besoin d'informer le programme d'un évènement, il change la valeur de l'entrée. Le processeur interrompt alors l'exécution du programme, et exécute la routine vers laquelle il est configuré pour pointer lors de l'interruption. Une fois cette routine exécutée, l'entrée reprend sa valeur initiale, et l'exécution du programme continue là où elle s'était arrêtée.
Tout comme le polling, cette technique possède des avantages et des inconvénients, mais les interruptions possèdent un panel très varié : touches pressées, évènement Wifi, fin de transfert DMA ...

La DS possède 23 interruptions ; le tableau suivant les liste, indique le processeur qui y a accès, et donne une brève description de ces dernières.

Nom|Bit|Processeur|Description
IRQ_VBLANK|0|ARM9 & ARM7|Générée lors de la période de VBlank.
IRQ_HBLANK|1|ARM9 & ARM7|Générée lors de la période de HBlank.
IRQ_VCOUNT|2|ARM9 & ARM7|Générée lorsque la valeur du VCOUNT correspond à la valeur configurée dans DISPSTAT.
IRQ_TIMER0|3|ARM9 & ARM7|Générée lors du débordement du timer 0.
IRQ_TIMER1|4|ARM9 & ARM7|Générée lors du débordement du timer 1.
IRQ_TIMER2|5|ARM9 & ARM7|Générée lors du débordement du timer 2.
IRQ_TIMER3|6|ARM9 & ARM7|Générée lors du débordement du timer 3.
IRQ_NETWORK|7|ARM7|
IRQ_DMA0|8|ARM9 & ARM7|Générée lors de la fin d'un transfert DMA sur le canal 0.
IRQ_DMA1|9|ARM9 & ARM7|Générée lors de la fin d'un transfert DMA sur le canal 1.
IRQ_DMA2|10|ARM9 & ARM7|Générée lors de la fin d'un transfert DMA sur le canal 2.
IRQ_DMA3|11|ARM9 & ARM7|Générée lors de la fin d'un transfert DMA sur le canal 3.
IRQ_KEYS|12|ARM9 & ARM7|Générée lorsque la valeur des touches pressées est égale à la valeur stockée dans REG_KEYCNT.
IRQ_CART|13|ARM9 & ARM7|Générée par la cartouche GBA.
IRQ_IPC_SYNC|16|ARM9 & ARM7|Générée lors de la synchronisation de l'IPC.
IRQ_FIFO_EMPTY|17|ARM9 & ARM7|Générée lors de l'envoi d'un FIFO vide.
IRQ_FIFO_NOT_EMPTY|18|ARM9 & ARM7|Générée lors de la réception d'un FIFO vide.
IRQ_CARD|19|ARM9 & ARM7|Générée à la fin d'un transfert de données depuis la carte.
IRQ_CARD_LINE|20|ARM9 & ARM7|
IRQ_GEOMETRY_FIFO|21|ARM9|Interruption géométrie FIFO.
IRQ_LID|22|ARM7|
IRQ_SPI|23|ARM7|Interruption du bus SPI.
IRQ_WIFI|24|ARM7|Générée lorsqu'un évènement Wifi se produit.
IRQ_ALL|~0|ARM9 & ARM7|L'ensemble des interruptions.


On peut activer chaque interruption en activant le bit correspondant dans le registre REG_IE, registre 32 bits situé à l'adresse 0x04000210.
De plus, il peut être utile de désactiver momentanément toutes les interruptions. Pour cela, le bit 0 du registre REG_IME, registre 16 bits situé à l'adresse 0x04000208, permet de désactiver toutes les interruptions lorsqu'il est mis à 0, que le bit de l'interruption soit activé ou non dans le registre REG_IE.

La libnds propose plusieurs fonctions pour gérer les interruptions :


une fonction d'initialisation globale


void irqInit();


2 fonctions permettant respectivement d'associer une fonction à une interruption, ou de supprimer la fonction associée à cette interruption


/* Associer : */
void irqSet(IRQ_MASK irq, VoidFunctionPointer handler);
/* Effacer : */
void irqClear(IRQ_MASK irq);


2 fonctions, permettant respectivement d'activer ou de désactiver une interruption


/* Activer : */
void irqEnable(IRQ_MASK irq);
/* Désactiver : */
void irqDisable(IRQ_MASK irq);


une fonction permettant d'utiliser un "interrupt handler" différent de celui utilisé par la libnds


void irqInitHandler(VoidFunctionPointer handler);




8.2 Interruptions softwares

Dans la partie précédente, j'ai usé et abusé du terme d'interruption. en réalité, c'est un abus de langage, et les interruptions précédentes étaient en réalité des interruptions hardwares. Il existe un autre type d'interruptions, qui fonctionnent comme les interruptions hardware, mais qui sont déclenchées par le programme lui-même. On appelle ces interruptions interruptions softwares (abréviation : SWI, pour SoftWare Interrupt).

Pour utiliser une interruption software, il suffit d'utiliser l'instruction ARM swi. Même s'il est possible d'utiliser cette instruction en C via asm(), on préfèrera utiliser les fonctions libnds correspondantes, lorsqu'elles existent. La DS possède 25 interruptions softwares, que le tableau suivant récapitule, tout en leur associant les fonctions libnds qui leur correspondent.

Valeur|Processeur|Fonction|Fonction libnds|Explication des paramètres
00h|ARM9 & ARM7|Effectue un reset software de la DS.|void swiSoftReset(void);|-
03h|ARM9 & ARM7|Attends un certain temps.|void swiDelay(uint32 duration);|duration est la durée à attendre.
04h|ARM9 & ARM7|Attends une interruption hardware.|void swiIntrWait(int waitForSet, uint32 flags);|Si waitForSet vaut 0, retourne si l'interruption a déjà eu lieu. Si waitForSet vaut 1, attend que l'interruption ait lieu. flags est l'interruption à attendre.
05h|ARM9 & ARM7|Attends l'interruption VBL.|void swiWaitForVBlank(void);|-
06h|ARM9 & ARM7|Stoppe le processeur|void swiHalt(void);|-
07h|ARM7|Mise en veille|void swiSleep(void);|-
08h|ARM7|change le registre SOUNDBIAS|void swiChangeSoundBias(int enabled, int delay);|enabled est le niveau de BIAS, delay est le délai (ex.: 8 sur GBA).
09h|ARM9 & ARM7|Division et modulo signé|int swiDivide(int numerator, int divisor);| numerator est le numérateur, et divisor le diviseur. Retourne le quotient.
Idem|Idem|Idem|int swiRemainder(int numerator, int divisor);| numerator est le numérateur, et divisor le diviseur. Retourne le modulo.
0Bh|ARM9 & ARM7|Copie|void swiCopy(const void * source, void * dest, int flags);|Les bits 0-20 de flags correspondent à la taille du transfert, le bit 24 au type de transfert (COPY_MODE_COPY ou COPY_MODE_FILL, copie ou remplissage) et le bit 26 à la taille du transfert(COPY_MODE_HWORD ou COPY_MODE_WORD, demi-mot ou mot).
0Ch|ARM9 & ARM7|Copie rapide|void swiFastCopy(const void * source, void * dest, int flags);|Les bits 0-20 de flags correspondent à la taille du transfert et le bit 24 au type de transfert (COPY_MODE_COPY ou COPY_MODE_FILL, copie ou remplissage).
0Dh|ARM9 & ARM7|Racine carrée|int swiSqrt(int value);|value est le nombre dont on cherche la racine carrée.
0Eh|ARM9 & ARM7|Retourne le CRC-16|uint16 swiCRC16(uint16 crc, void * data, uint32 size);|crc est le CRC-16 initial, data est un pointeur vers les données, et size est la taille des données en octets.
0Fh|ARM9 & ARM7|Retourne 1 si le programmer tourne sur debuggeur hardware.|int swiIsDebugger(void);|-
10h|ARM9 & ARM7|Récupère chaque bit d'un champ de bits dans un octet.|void swiUnpackBits(uint8 * source, uint32 * destination, PUnpackStruct params);|source est l'adresse du champ de bits, destination est l'adresse de récupération des bits en octet, et params est la structure de paramètres.
11h|ARM9 & ARM7| |void swiDecompressLZSSWram(void * source, void * destination);|
12h|ARM9 & ARM7| |int swiDecompressLZSSVram(void * source, void * destination, uint32 toGetSize, TDecompressionStream * stream);|?
13h|ARM9 & ARM7| |int swiDecompressHuffman(void * source, void * destination, uint32 toGetSize, TDecompressionStream * stream);|?
14h|ARM9 & ARM7| |void swiDecompressRLEWram(void * source, void * destination);|
15h|ARM9 & ARM7| |int swiDecompressRLEVram(void * source, void * destination, uint32 toGetSize, TDecompressionStream * stream);|?
16h|ARM9| |extern void swiDecodeDelta8(void * source, void * destination);|
18h|ARM9| |void swiDecodeDelta16(void * source, void * destination);|
1Ah|ARM7|Récupère un sinus.|uint16 swiGetSineTable(int index);|index est l'entier dont on souhaite calculer le sinus.
1Bh|ARM7|Récupère un pitch.|uint16 swiGetPitchTable(int index);|index est l'index du pitch recherché dans la table.
1Ch|ARM7|Récupère un volume dans la table des volumes.|uint8 swiGetVolumeTable(int index);|index est l'index du volume.
1Dh|ARM9 & ARM7| | |
1Fh|ARM9|Ecriture dans le registre POSTFLG.|-|-
1Fh|ARM7|Ecriture dans le registre HALTCNT.|-|-


Pour utiliser les interruptions softwares qui ne sont pas gérées par la libnds, il faut utiliser du code ARM, mais cela dépasse les limites de ce tutoriel. Heureusement, ces quelques fonctions sont très peu utilisées.


9. Inter Processor Communication (IPC)


10. Mots de la fin

10.1 Remerciements

Je voudrais remercier :

Dr.Vince pour les modifications qu'il a apporté au système de BBCode, notamment sur les tableaux, et pour ses conseils.
Arcadia, pour ses news, toujours aussi amusantes, et qui font franchement plaisir !
Foxy, Noda et simonomis pour les corrections de coquilles
Ceux que j'ai dû oublier ...


10.2 Liens


Téléchargement de devkitpro : http://sourceforge.net/project/showfiles.php?group_id=114505
Téléchargement de la libnds : http://sourceforge.net/project/showfiles.php?group_id=114505&package_id=151608
L'excellente GBATek, de Martin Korth : http://nocash.emubase.de/gbatek.htm
DSTek, de Neimod : http://neimod.com/dstek/



## Partie B, Pratique : ShootMe


Cette seconde partie est un complément à la première, et consiste en une application des notions abordées dans la partie documentation en utilisant bien sûr le langage C. Elle vous montrera, par l'intermédiaire de la création d'un petit jeu, ShootMe, comment utiliser tout ce que je présente plus haut.
Comme son nom l'indique, cet homebrew sera un FPS, avec tout ce qui tourne autour, ce qui permettra d'aborder tout et n'importe quoi.

Attention : comme je ne rédige pas la partie théorique de façon linéaire, les exercices présents dans cette seconde partie sont dans un ordre qui ne suit pas l'ordre de la première partie. Il faut donc parcourir le tout, ou lire chaque passage au fur et à mesure que le besoin s'en fait. Pour ce faire, chaque exercice est numéroté, en rapport avec le passage auquel il se rapporte, et non de manière linéaire.

Bonne lecture, et bons tests !


Exercice 1.0 Une console pour notre jeu

Le but de ce premier exercice est très simple : initialiser une console sur l'écran secondaire, et échanger les 2 écrans, pour obtenir un espace de communication avec l'utilisateur pendant la phase d'initialisation. Tout ça dans une fonction qui nous servira de fonction d'initialisation :


static inline void Initialize(void);


Ensuite, il faudra ajouter un appel à cette fonction dans le main, et afficher le texte suivant : "ShootMe\n-------\n\n".

AIDE : pour échanger les 2 écrans et mettre l'écran principal en haut, il faut utiliser la fonction lcdMainOnTop() ; pour faire l'inverse, il faut utiliser la fonction lcdMainOnBottom(). Ceci est utile, car seul l'écran principal est capable d'afficher de la 3D, par exemple.


Correction 1.0 Une console pour notre jeu


#include <nds.h>
#include <stdio.h>

static inline void Initialize(void);

int main(int argc, char * argv[])
{
Initialize();

iprintf("ShootMe\n-------\n\n");

while (1)
{
swiWaitForVBlank();
}

return 0;
}

static inline void Initialize(void)
{
irqInit();
irqSet(IRQ_VBLANK, 0);

lcdMainOnTop();

videoSetMode(0);
videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE);

vramSetBankC(VRAM_C_SUB_BG);

SUB_BG0_CR = BG_MAP_BASE(31);

BG_PALETTE_SUB[255] = RGB15(31, 31, 31);

consoleInitDefault((u16 *) SCREEN_BASE_BLOCK_SUB(31), (u16 *) CHAR_BASE_BLOCK_SUB(0), 16);
}

Arcadia
11/03/2007, 21h33
Bonne initiative ! Ça mérite une petite new ^^...


[EDIT] Et voili... :whst:

Au fait, il faudrait peut-être mettre les liens ou on peut toruver la lib non ? J'ai mis un site en page d'accueil mais je ne suis pas sûr que ce soit le bon, par manque de temps je ne peux pas trop vérifier...

DJP
11/03/2007, 21h55
Génial ;)
Perso je n'utilise aussi que la libnds :D

Smealum
11/03/2007, 21h55
Je sens que ça va aider des gens ça :)
Personnellement, je me suis mis à libnds il y a un bout de temps et la seule chose que je lui reproche, c'est son manque de documentation...c'est vraiment horrible : il n'existe qu'une doc, mais elle date de l'époque où libnds s'appelait ndslib (il y a très longtemps donc :p)

Foxy
11/03/2007, 22h00
Juste un petit bémol, tu compares les fonction keysDown() et keysHeld(), elles ne font pas tout a fait la même chose !
Si l'on maintient une touche appuyée, KeysDown() ne la renverra que lors de l'appui et ensuite renverra zero, alors que keysHeld() renverra la valeur de la touche tant que celle ci sera appuyée.

(La précision est importante pour ceux qui n'ont pas forcément un niveau d'anglais suffisant).

Pitt
11/03/2007, 22h17
Merci pour vos commentaires, c'est encourageant ! v_v Et merci beaucoup pour la news, Arcadia, ça fait très plaisir !
Je vais rajouter le lien pour la lib, et modifier pour le keysDown() / keysHeld() (très juste, j'avais complètement oublié). :)
Surtout, corrigez-moi si j'ai écrit une annerie, je me suis relu, mais on n'est jamais à l'abri ... :rolleyes: Pareil si vous avez besoin de précisions !

Dr.Vince
11/03/2007, 22h36
franchement bravo !!!!

ça fait un moment que je voulais faire ça mais j'ai jamais eu le temps de me pencher sur la libnds !!!

Doud_
11/03/2007, 22h37
Merci beaucoup Pitt!

Je regarde tout ça au plus vite ;)

Bon courage pour la suite des tutos :-'

Pitt
11/03/2007, 22h42
Merci ! :-'

@ Modos & admins >> Pour la suite du tuto, vous préférez que je crée d'autres topics, ou que je continue sur le même ? :huh:

Dr.Vince
11/03/2007, 23h01
hum.... continue sur le même ça nous évitera du boulot par la suite :whst: (CQP)

bah en fait y a que moi pour le CQP ;)

DJP
11/03/2007, 23h11
hum.... continue sur le même ça nous évitera du boulot par la suite :whst: (CQP)

bah en fait y a que moi pour le CQP ;)
Je pense pouvoir comprendre aussi mon petit gars ... ;)

Pitt
11/03/2007, 23h13
:lol: J'ai pas tout compris, même si j'ai quand même une petite idée sur la question ...
En tout cas, message reçu, la suite bientôt, au même endroit ! :)

pmcc
11/03/2007, 23h23
C'est clair qu'il manque une certaine documentation autour de la libnds. Je m'y suis mis il y a presque un mois et J'ai recherché plein d'infos la première semaine sur le hardware DS et la lib avant de réellement commencer à coder donc des tutos dessus sont toujours les bienvenues :).
D'ailleurs je pense sortir mon premier homebrew avec le code source, ca peut toujours aider.

mastertop101
11/03/2007, 23h38
Merci !! Ça doit bien être le seul tutoriel francophone pour libnds ! (?)

Continue comme ça!

DJP
11/03/2007, 23h58
Et encore, pour la libnds il y a beaucoup d'exemples, relativement bons...mais la libgba...

simonomis
12/03/2007, 12h20
ca y est, tu m'a donné l'envie de me lancer dans le dev ds. En plus en ce moment j'ai un peu de temps devant moi, donc ca tombe bien :D
je t'en remercie ;)

reste plus qu'à comprendre comment marche devkitpro maintenant >_<

à bientot dans la section DEV ;)

Pitt
12/03/2007, 17h54
Et encore, pour la libnds il y a beaucoup d'exemples, relativement bons...mais la libgba...

Ce qui sous-entend ... ? :lol:

ca y est, tu m'a donné l'envie de me lancer dans le dev ds. En plus en ce moment j'ai un peu de temps devant moi, donc ca tombe bien
je t'en remercie ;)

reste plus qu'à comprendre comment marche devkitpro maintenant >_<

à bientot dans la section DEV ;)

Content d'avoir créé des vocations ! :-' Devkitpro, c'est hyper simple, il n'y a (presque) rien à comprendre ! ^^

Je vais mettre en ligne un petit quelque chose ce soir, pas grand chose, j'ai un devoir de maths à faire ... <_< Facile et long, il n'y a pas plus chiant ... :lol:

A part ça 'faudrait corriger le lien dans la new, il n'y a pas de site officiel à proprement parler pour la libnds. ^^

barjo
12/03/2007, 18h13
Merci beaucoup pour ce début de tuto ces simpa :-'

Pourquoi les personnes qui utilise la libnds ne préfére pas la palib ?
Elle est pourtant beaucoup plus documenté avec de trés bonne explications sur le wiki.:-*

Pitt
12/03/2007, 18h32
La libnds permet de gérer le hardware DS. La PAlib est plutôt orientée simplicité, avec tout plein de fonctions d'abstraction du hardware.
En gros, la libnds, c'est plus pour les curieux, les puristes, etc. ;)

Lazarus
12/03/2007, 18h47
Pourquoi les personnes qui utilise la libnds ne préfére pas la palib ?
Elle est pourtant beaucoup plus documenté avec de trés bonne explications sur le wiki.
Ben, déjà, la documentation ne fait pas non plus la lib :)

Sinon, on ne va pas refaire tout le débat, mais libnds est très orienté proche du hardware, avec un contrôle total sur la DS, mais du coup un peu plus de choses à comprendre avant de commencer et de maitriser la bête, alors que PAlib est orienté simplicité, donc a des fonctions toutes faites pour cacher pas mal de petites choses.

Au final, il en ressort que la PAlib est plus simple pour débuter (après, ca dépend pour qui, si tu maitrises déjà bien le C, ca va, si tu as dev sur GBA aussi, etc...), et que les codeurs 'avertis' préfèrent libnds pour la souplesse.

PAlib te permet de faire rapidement des choses sympas, mais libnds te permet à terme de mieux comprendre la DS en elle-même, ce qui est un but en soi pour certains. :)

Smealum
12/03/2007, 19h24
Et puis, PAlib et la 3D, c'est pas trop ça :p

barjo
12/03/2007, 19h30
Ok merci pour les réponses v_v

Lazarus
12/03/2007, 19h42
Et puis, PAlib et la 3D, c'est pas trop ça
Là, désolé, je suis pas d'accord. Je dirais que c'est pas du tout ça ^^ En gros, pour la 3d, c'est libnds, point barre. En pratique on peut utiliser PAlib pour la 2D et libnds pour la 3D dans un meme projet par contre :)

Smealum
12/03/2007, 19h45
Ca n'empêche qu'il existe existe des fonctions 3D dans PAlib et...ben voilà quoi :p

Lazarus
12/03/2007, 19h48
Oui et non... Enfin, il y a bien des fonctions 3D, d'init par exemple, qui permettent d'utiliser sans aucun soucis libnds derriere.

Les autres fonctions plus 'avancées' ne sont pas à proprement parler de la 3D pure et dure, c'est juste une utilisation des textures pour faire des sprites, ce qui a ses avantages et ses inconvénients ^^

Ludo6431
12/03/2007, 20h53
Bravo,
il y a longtemps que j'attendais un TUTO de ce genre pour me mettre à programmer.
Je te remercie de partager ton savoir !!!!!!

Arcadia
12/03/2007, 21h13
Puisqu'on parle de PAlib, le PA veut dire PA ou pas ? :whst:




Me tapez pas, c'était pour déconner :-'

Lazarus
12/03/2007, 21h30
Programmer's Arsenal ;)

Arcadia
12/03/2007, 22h04
Programmer's Arsenal ;)

Depuis toujours ? :ange: ....Non je taquine ^^

En tout cas, sans chercher à me mettre au codage sur DS (trop de défi à finir sur GBA avant), je m'interesse de loin à ces librairies. C'est du bon boulot qu'on fait les créateurs de ces librairies, sur GBA on avait pas ce luxe :) ! (Ham est super, mais payant)

cyberxander
12/03/2007, 22h42
hello tout le monde^^
J'ai installé devkitpro avec la librairie libnds.
J'aurais voulu savoir comment compiler les exemples du tuto si quelqu'un peut m'aider, je fouille les forum depuis tout à l'heure mais je ne trouve que des exemple pour la PAlib(que j'arrive a compiler mais pas les exemples du tuto avec la libnds).en fait je crois qu'il me faut un makefile j'aimerais bien comprendre comment ça fonctionne...

pmcc
12/03/2007, 22h52
hello tout le monde^^
J'ai installé devkitpro avec la librairie libnds.
J'aurais voulu savoir comment compiler les exemples du tuto si quelqu'un peut m'aider, je fouille les forum depuis tout à l'heure mais je ne trouve que des exemple pour la PAlib(que j'arrive a compiler mais pas les exemples du tuto avec la libnds).en fait je crois qu'il me faut un makefile j'aimerais bien comprendre comment ça fonctionne...

Tu as des Makefile de base dans un des repertoires des exemples de la libnds (exampes/template de tête).
"arm9" si tu ne fournis que le code pour l'arm9 (un binaire arm7 avec une gestion basique du son plus 2, 3 trucs est alors utilisé) et "combined" si tu fournis les 2 binaires.
Si t'es sous Windows regarde le setup d'un projet DS sur le site de devKitPro et sous unix ba t'as rien à faire :)

cyberxander
12/03/2007, 23h08
Tu as des Makefile de base dans un des repertoires des exemples de la libnds (exampes/template de tête).
"arm9" si tu ne fournis que le code pour l'arm9 (un binaire arm7 avec une gestion basique du son plus 2, 3 trucs est alors utilisé) et "combined" si tu fournis les 2 binaires.
Si t'es sous Windows regarde le setup d'un projet DS sur le site de devKitPro et sous unix ba t'as rien à faire :)

merci bien je vais voir ça de suite!

cyberxander
12/03/2007, 23h24
ça fonctionne, merci encore^^

MIKEGBA
12/03/2007, 23h32
>_< dire que j'allais passer à coté de ton topic !

Bravo Pitt, belle initiative de ta part, j'espère que la suite va bientot arriver :D

En tout cas j'espere que ton tuto va faire naitre de nombreuses vocations pour le codage un peu "hard" et que l'on va voire fleurir de beaux projets grâce à toi :)

Bonne continuation.;)

M@cZér0
13/03/2007, 00h46
Puisqu'on parle de PAlib, le PA veut dire PA ou pas ? :whst:




Me tapez pas, c'était pour déconner :-'


:lol: Je vois que ton message a été édité... On t'avais déjà tapé avant que t'implore pitié??:whst:

edit : Un petit lien en page d'accueil section Cours et tutoriel?? Mon petit tuto sur MoonShell commence à s'ennuyer qu'avec des liens anciens...:cry:

cyberxander
13/03/2007, 01h10
Tu as des Makefile de base dans un des repertoires des exemples de la libnds (exampes/template de tête).
"arm9" si tu ne fournis que le code pour l'arm9 (un binaire arm7 avec une gestion basique du son plus 2, 3 trucs est alors utilisé) et "combined" si tu fournis les 2 binaires.
Si t'es sous Windows regarde le setup d'un projet DS sur le site de devKitPro et sous unix ba t'as rien à faire :)
bon j'ai reussi à compiler un helloworld mais si je change le texte où la couleur à afficher, rien ne change sur le *.nds obtenu..... j'ai choppé la migraine là...

Arialia
13/03/2007, 01h36
bon j'ai reussi à compiler un helloworld mais si je change le texte où la couleur à afficher, rien ne change sur le *.nds obtenu..... j'ai choppé la migraine là...

Si tu es sous windows , en double cliquant sur le fichier "hello_world.pnproj"
Programmeur notepad se lance pour le projet
tu fais tes modifications , tu enregistres et tu fais "Menu Outils/Make" ça recompilera ...

Avec make il faut que tu sois à la racine de ton projet ...=_=

Samote
13/03/2007, 17h46
Super ton tuto. Moi qui voulait me mettre a libnds.
Vivement la suite ! :D

Pitt
13/03/2007, 21h11
Merci à tous pour vos commentaires, ça fait vraiment plaisir ! :w00t:

Je viens de mettre en ligne la partie 2, même si elle n'est pas complètement terminée.
Pour appliquer le tuto, il faut utiliser le template arm9 des exemples libnds. Je l'ai peut-être mal dit, je corrigerai un peu plus tard.

Bonne lecture, et comme d'habitude, je suis ouvert à toute proposition / correction de bourdes / etc. ^^

cyberxander
14/03/2007, 00h30
yes, en utilisant le template de l'arm9 ça marche nickel! à moi le dev sur DS!
merci à toi pitt pour ce tuto, je vais de ce pas voir le nouveau^^

Pitt
14/03/2007, 15h04
Nouvelle version en ligne. Toujours pas fini le tableau des interruptions, mais j'ai rajouté une partie sur le Vcount, le HBL, le VBL, les timers et les transferts DMA. ;)

Vu 616 fois, un seul commentaire depuis la dernière partie ... Ca veut dire que ça intéresse du monde ? :huh:

Samote
14/03/2007, 19h54
Oui oui sa intéresse !!! :w00t:

cyberxander
14/03/2007, 20h09
je confirme ça interesse^^

barjo
14/03/2007, 20h42
Moi aussi sa m'intérése :wub:
Continue comme sa v_v

Pitt
14/03/2007, 20h52
Ma petite phrase a eu de l'effet, visiblement :p ... Merci ! v_v
Besoin de précisions, quelque chose de mal expliqué ? :)

Pour les admins/modos :
* Serait il possible d'utiliser des '|' dans les tableaux ?
* Pourrait-on avoir un système d'ancres, pour faire un sommaire ?
=_= Je poste ici, j'ai vu qu'il y avait quelques personnes du staff qui trainaient dans le coin ...

Arcadia
14/03/2007, 21h29
Oups, j'ai pas vu l'évolution du topic avant. Je fais une petite info sur le portail ^^.

Quand à ta demande concernant les tableaux Pitt, je te conseille d'envoyer un mp à Dr.Vince :)

Arialia
14/03/2007, 23h25
très sympa ton tuto, très intéressant, continue comme çà ,c'est génial !!!:w00t:

Moi je croyais que le DMA justement était réalisé par un sous-processeur ou par une puce ce qui permettait de soulager le processeur ( désolée mes connaissances viennent du PC, je crois que c'était comme ça pour le son avec la Soundblaster :unsure: ) pour la DS c'est pas le cas alors? :blink:

Pitt
14/03/2007, 23h31
Non, non, le processeur est interrompu. ^^ Ca peut paraitre bizarre au début, surtout quand on connait d'autres architectures, mais c'est comme ça ! :)

Merci beaucoup pour la news, Arcadia ! v_v J'ai vu Dr.Vince pour les histoires de tableaux. ;)

pmcc
15/03/2007, 09h13
très sympa ton tuto, très intéressant, continue comme çà ,c'est génial !!!:w00t:

Moi je croyais que le DMA justement était réalisé par un sous-processeur ou par une puce ce qui permettait de soulager le processeur ( désolée mes connaissances viennent du PC, je crois que c'était comme ça pour le son avec la Soundblaster :unsure: ) pour la DS c'est pas le cas alors? :blink:

Si si tu as plus ou moins raison pour le DMA, c'est sensé être asynchrone et le CPU n'intervient pas une fois le transfert démarré, une interruption le prévennant une fois que celui-ci est terminé.
Ca marche pareil sous DS sauf que les fonctions dmaCopy* ne sont pas asynchrones puisqu'elles attendent que le port DMA utilisé pour le transfert redevienne disponible (donc ca bloque). Tu as quand même la possibilité de transférer en asynchrone avec les fonctions dmaCopy*Async, qui là ne bloqueront pas donc.

Reppa
15/03/2007, 14h18
Ca à franchement pas l'air évident libnds. Si on n'avait pas la palib pour ceux qui ont plus de mal à comprendre le developpement, on n'aurait peu de homebrew sur ds finalement ^^

Enfin très jolie travail pour ce post

Noda
15/03/2007, 21h22
Cet exemple utilise le canal 3, et copie des octets (même si on utilise une taille en mots, puisqu'on divise cette taille par 2 ;)). Vous pouvez bien entendu utiliser un autre canal, ou encore transférer des mots (DMA_COPY_WORDS) plutôt que des octets (DMA_COPY_HALFWORDS).


Si je ne m'abuse un mot (word) c'est 32 bits donc 4 octets, et un halfword 16 bits soit 2 octets ;)

Pitt
15/03/2007, 23h11
Si je ne m'abuse un mot (word) c'est 32 bits donc 4 octets, et un halfword 16 bits soit 2 octets ;)

Très juste, merci pour la correction de coquilles. ^^

Dr.Vince
16/03/2007, 00h48
* Serait il possible d'utiliser des '|' dans les tableaux ?


C'est fait, il suffit juste de doubler le caractère |

Pitt
16/03/2007, 23h03
T'es génial ! :wub:

Foxy
16/03/2007, 23h12
Si je ne m'abuse un mot (word) c'est 32 bits donc 4 octets, et un halfword 16 bits soit 2 octets ;)
Hmm.. Normalement un WORD c'est 16 bits et un DWORD c'est 32 bits.

Brunni
17/03/2007, 01h19
En C sous Windows (et probablement ailleurs) c'est comme ça, mais dans le jeu d'instructions d'ARM c'est word = 32 et halfword = 16, je n'ai d'ailleurs jamais vraiment compris, il ne doit pas y avoir de standard :S

Foxy
17/03/2007, 01h22
Merci pour l'info Brunni, au moins c'est plus clair là :)

Arialia
17/03/2007, 11h14
tiré de wikipedia :En plus du système de représentation des nombres, il faut s'intéresser à la taille et la précision des nombres qu'un processeur peut manipuler. Dans le cas d'un processeur binaire, un "bit" correspond à une position particulière dans les nombres que le processeur peut gérer. Le nombre de bits (chiffres) qu'un processeur utilise pour représenter un nombre est souvent appelé "taille du mot" (word size, bit width, data path width) ou "précision entière" lorsqu'il s'agit de nombres entiers (à l'opposé des nombres flottants). Ce nombre diffère suivant les architectures, et souvent, suivant les différents modules d'un même processeur. Par exemple, un CPU 8-bit gère des nombres qui peuvent être représentés par 8 chiffres binaires (chaque chiffre pouvant prendre 2 valeurs), soit 28 ou 256 valeurs discrètes. En conséquence, la taille du nombre entier défini une limite à la plage des nombres entiers que le logiciel exécuté par le processeur pourra utiliser.
Donc comme l'arm est 32 bits la taille du mot est donc 32 bits, c'est pour ça que pour le compilateur un word est sur 32 bits...

Sur PC, il faut tenir compte de l'historique : le 8086 est un processeur 16 bits ainsi que le 80286 les premiers compilateurs pc sont nés à cette époque et donc un "word" était sur 16 bits, apparemment certains compilateurs sur Pc ont donc gardé cette taille pour la compatibilité du code ...

donc attention à la taille du "word" tout dépend du processeur ciblé et du compilateur ....:rolleyes:

Pitt
17/03/2007, 21h49
Oui, effectivement, c'est très aléatoire, d'où la confusion que j'avais faite dans le tuto ... v_v
En tout cas, update demain, avec restructuration totale du tuto ... :)

Aigle d'or
17/03/2007, 22h17
Si dans le langage courant, on parle de mot machine, c'est pour bien sous entendre que la taille du mot est lié au processeur qui le manipule.

Pitt
18/03/2007, 19h53
Finalement, pas de nouvelle version aujourd'hui, mais je suis en train de refaire complètement le tuto, tout en l'améliorant ...

simonomis
23/03/2007, 18h20
On va maintenant désactiver l'écran tactile, qui ne nous sert à rien, en ne lui affectant aucun mode graphique.
Par contre, on initialise l'écran du haut, sur lequel on va écrire notre texte, au mode graphique nécessaire, c'est-à-dire le mode 0 2D. On va également activer un des fonds, le fond 0.
Les fonds sont des couches superposées, qui gèrent la transparence, et qui permettent d'utiliser plusieurs "niveaux" d'affichage. ;)

videoSetMode(0);
videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE);
ce n'est pas l'inverse qui est fait avec ce code ?!
chez moi, quand je tape ca, l'ecran du haut est desactivé et le texte est en bas...

pmcc
23/03/2007, 19h02
ce n'est pas l'inverse qui est fait avec ce code ?!
chez moi, quand je tape ca, l'ecran du haut est desactivé et le texte est en bas...

Il a peut-être inversé les 2 écrans (de tête SwapLcd()).

Pitt
23/03/2007, 19h10
arf, oui, j'avais inversé mes écrans dans mon code de test, et j'avais pas vérifié cette partie du code ...
bon, je corrigerai, mais de toute façon, le tuto revient dans pas longtemps, sous une tout autre forme, et en beaucoup mieux ! ^^

mastertop101
25/03/2007, 21h01
Salut, j'ai essayé de compiler et je me retrouve avec plusieurs problèmes (et je ne suis pas le seul à en avoir)


C:\devkitPro\ESSAIS_LIBNDS\arm9>make
main.c
arm-eabi-gcc -MMD -MP -MF /c/devkitPro/ESSAIS_LIBNDS/arm9/build/main.d -g -Wall -O2 -march=armv5te -mtune=arm946e-s -fomit-frame-pointer -ffast-math -mthumb -mthumb-interwork -I/c/devkitPro/ESSAIS_LIB
NDS/arm9/include -I/c/devkitPro/libnds/include -I/c/devkitPro/ESSAIS_LIBNDS/arm9/build -DARM9 -c /c/devkitPro/ESSAIS_LIBNDS/arm9/source/main.c -o main.o
c:/devkitPro/ESSAIS_LIBNDS/arm9/source/main.c: In function 'main':
c:/devkitPro/ESSAIS_LIBNDS/arm9/source/main.c:10: warning: implicit declaration of function 'BG_MAP_BG'
c:/devkitPro/ESSAIS_LIBNDS/arm9/source/main.c:11: warning: implicit declaration of function 'RGB'
c:/devkitPro/ESSAIS_LIBNDS/arm9/source/main.c:15:3: warning: no newline at end of file
linking arm9.elf
main.o: In function `main':
c:/devkitPro/ESSAIS_LIBNDS/arm9/source/main.c:10: undefined reference to `BG_MAP_BG'
c:/devkitPro/ESSAIS_LIBNDS/arm9/source/main.c:11: undefined reference to `RGB'
collect2: ld returned 1 exit status
make[1]: *** [/c/devkitPro/ESSAIS_LIBNDS/arm9/arm9.elf] Error 1
make: *** [build] Error 2

C:\devkitPro\ESSAIS_LIBNDS\arm9>pause
Press any key to continue . . .


Et mon code :


#include <nds.h>
#include <stdio.h>
int main (void){
irqInit();
irqSet(IRQ_VBLANK,0);
videoSetMode(0);
videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE);
vramSetBankC(VRAM_C_SUB_BG);
SUB_BG0_CR=BG_MAP_BG(31);
BG_PALETTE_SUB[255] = RGB(31, 31, 31);
consoleInitDefault((u16*)SCREEN_BASE_BLOCK_SUB(31) ,(u16*)CHAR_BASE_BLOCK_SUB(0),16);
iprintf("Hello world !\n");
return 0;
}

Utilisant le template :
C:\devkitPro\examples\nds\templates\arm9

Merci de votre aide

pmcc
25/03/2007, 22h13
Salut, j'ai essayé de compiler et je me retrouve avec plusieurs problèmes (et je ne suis pas le seul à en avoir)




Et mon code :


#include <nds.h>
#include <stdio.h>
int main (void){
irqInit();
irqSet(IRQ_VBLANK,0);
videoSetMode(0);
videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE);
vramSetBankC(VRAM_C_SUB_BG);
SUB_BG0_CR=BG_MAP_BG(31);
BG_PALETTE_SUB[255] = RGB(31, 31, 31);
consoleInitDefault((u16*)SCREEN_BASE_BLOCK_SUB(31) ,(u16*)CHAR_BASE_BLOCK_SUB(0),16);
iprintf("Hello world !\n");
return 0;
}

Utilisant le template :
C:\devkitPro\examples\nds\templates\arm9

Merci de votre aide

RGB15 à la place de RGB, et BG_MAP_BASE pour BG_MAP_BG.

Pitt
25/03/2007, 22h52
:o arf oui, j'étais pas inspiré le soir où j'ai écrit ça ?! :blink:
Bon, bientôt une nouvelle version, et sans les bugs ...>_<
Personne ne l'avait remarqué avant ? :|

Arialia
25/03/2007, 23h06
Oh ! :-' je l'avais pas remarqué j'ai du faire une correction automatique sans faire gaffe ! Le cerveau nous joue des tours des fois ....:whst:

Dr.Vince
26/03/2007, 00h42
le truc que tu devrais faire Pitt c'est tester les bouts de code avant de poster pour être sur qu'il n'y a pas de coquilles

Pitt
26/03/2007, 20h54
C'est ce que j'avais fait, mais comme j'avais utilisé plusieurs codes de test, j'ai juste du me tromper de fenêtre XD ...

P.S.: Regarde ta messagerie ! ^^

Pitt
26/03/2007, 22h39
Grosse update, pas énormément de nouveautés, mais c'est 3x plus précis, 3x plus structuré, et 3x plus long aussi ... ^^
Les commentaires/remarques/suggestions sont les bienvenus ... ;)

Enjoy !

Arialia
29/03/2007, 16h31
très bien Pitt :bravo:

du coup je viens de voir cette fonction :
swiDecompressHuffman

est-ce qu'en utilisant cette fonction je gagnerai du temps par rapport à la fonction équivalente de la jpeglib ou seulement de la mémoire( se serait déjà pas mal ...) ?

Foxy
29/03/2007, 18h08
De plus, la DS est Little Endian, donc les octets qui composent chaque mot ne sont pas inversés. Par exemple le double-mot 0xBADC0FEE sera stocké comme suit, c'est-à-dire exactement comme on l'écrit en hexadécimal :


2^Octet|0|1|2|3
Valeur|BA|DC|OF|EE

C'est le contraire ^^
C'est en Big Endian que les octets ne sont pas inversés, en Little Endian les octets se lisent de droite à gauche (comme sur PC).

Dr.Vince
29/03/2007, 18h38
effectivement Pitt,, faut que tu inverse l'entête du tableau 0123 -> 3210

Pitt
29/03/2007, 18h41
Arf tiens, j'ai appris un truc, je pensais sincèrement que c'était l'inverse ! v_v
Je corrige ! <_<

Pour la fonction swiDecompressHuffman, je l'ai pas encore testée, donc je ne sais pas ce qu'elle vaut, mais ça doit pouvoir optimiser un peu, en effet. ;)

Merci pour vos remarques !

EDIT : c'est fait !
@Dr.Vince >> je vais bientôt rajouter la 2ème "partie", enfin tu vois ce que je veux dire quoi ... ;)

Samote
29/03/2007, 19h22
Superbe tuto. Je vais enfin pouvoir me mettre a libnds.

Pitt
30/03/2007, 23h36
Ajout d'une partie exercice, avec la programmation progressive d'un petit FPS.

barjo
31/03/2007, 01h46
Ha merci ces super comme projet, surtout continue :)

pouer256
25/04/2007, 11h06
Super comme projet mais a quand la suite des cours :whst:

Pitt
25/04/2007, 12h37
Rhoo nan mais l'autre ! :lol:
Bientôt, bientôt !
Au programme, le côté Video 2D de la bestiole ! :w00t:

pouer256
26/04/2007, 19h07
super !!

Pitt
27/04/2007, 19h30
Ajout d'une partie sur l'unité LCD = "power management".
C'est pas grand chose, mais faut bien commencer qqpart ... ^^

@ modos/admins >> le système de modification rapide des messages c'est une super idée, mais ça bug pour mon tuto, je suis obligé de passer par l'interface avancée ... trop grand peut-être ?

Dr.Vince
27/04/2007, 21h45
aucune idée, mais on verra ça en début de semaine voir si ça plante toujours (CQP)

pouer256
18/06/2007, 19h06
Cool maintenant que les grande vacances arrive tu va pouvoir continuer ce tuto !

zomboula
27/03/2008, 16h10
Oui et non... Enfin, il y a bien des fonctions 3D, d'init par exemple, qui permettent d'utiliser sans aucun soucis libnds derriere.

Les autres fonctions plus 'avancées' ne sont pas à proprement parler de la 3D pure et dure, c'est juste une utilisation des textures pour faire des sprites, ce qui a ses avantages et ses inconvénients ^^

A quand le BASIC !?:ranting::ranting:sur nintendo ds biensûr...

Arialia
27/03/2008, 17h53
Oula Zomboula arrête de crier j'en ai mal aux oreilles >_<

Si tu veux un Basic sur DS fais-le !

Ou alors paye quelqu'un pour te le faire :na:

Sinon une recherche sur Google te permettra de savoir qu'il en existe un :whst:

ton message agressif n'a rien à faire sur ce topic >(

archipel
27/03/2008, 17h54
Il te reste plus qu'à t'y mettre <_<

EDIT : grilled