In the years the DS went through some upgrades, which made it lighter and with better LCD quality (the DS Lite). Then the available memory has been increased as well as the CPU speed (the DSi), and bigger screens were introduced later (the DSi XL). Finally, a stereoscopic screen was implemented (the 3DS, which is actually more like a new console with DS compatibility). Nintendo also joint ventured a Chinese entrepreneur to distribute its products in China under the iQue name. So we actually have also iQue DS, iQue DS Lite and iQue DSi, all featuring additional support for the Chinese language, which is not included in Nintendo's 'own' products.
Homebrew programs are not aware of the different models. Most of the programs that do run in DSi mode, using the ARM9 CPU at double speed (134 MHz) and the quadrupled main memory size (16 MB), aren't even aware of that. Few programs, however, detect if they're running on a DS Lite or newer, so they can drive the LCD brightness, which isn't possible on the 'original' DS.
The GBAtek document gives some information that could be useful for distinguishing the DS Lite from the 'original' DS model (often called DS 'phat' nowadays). It also contains a minimum of information regarding both iQue DS and iQue DS Lite models, but it lacks anything from DSi on. So I tried to collect as much data as possible from friends and on-line DS user communities... I would have expected some more help from the latter, but... well, ok.
From the details I collected it seems that the 01Dh location ('Console type') in the firmware header could also be used to detect if the model is a DSi, but unfortunately, it doesn't give any hint to distinguish if it's a 'normal' DSi or a DSi XL... or if it's a 3DS emulating a DSi. They all appear the same (the value there is always 0x57). I then noticed that at the 02Fh location ('Wifi version') I get different values for different console models: all the DSi models I have had tested have 0x0F, the DSi XL models have 0x18, and 3DS's have 0x1C.
I thus made a program (download it here) that should tell you which DS model you're holding in your hand. In case it's a DSi / DSi XL / 3DS the program will also tell you if your homebrew cartridge is working in DSi mode or not.
Unfortunately, I still don't know anything about the iQue DSi, and I also don't know if there is any other possible value for 'Wifi version' except for the ones I collected, so I actually speculated that any different value found should be assimilated to the closest lower valid value. If you have an iQue DSi or if you're running my program and it misses the correct answer, I'd really appreciate if you could run this little program and let me know what it writes on screen and which console model the program is running on.
Finally, here's the source code of the detection routine, which has to run on the ARM7. It uses the boolean variable __dsimode that is provided directly by libnds. I wrote the code using a sort of a 'successive refinement' so that if it misses the target it shouldn't miss it by too much. Hopefully. Use it as you wish in your own program, at your own risk.
#define MODEL_NINTENDO_DS 0
#define CHINESE_SUPPORT 1
#define MODEL_IQUE_DS (MODEL_NINTENDO_DS+CHINESE_SUPPORT)
#define MODEL_NINTENDO_DS_LITE 2
#define MODEL_IQUE_DS_LITE (MODEL_NINTENDO_DS_LITE+CHINESE_SUPPORT)
#define MODEL_NINTENDO_DSI 4
// #define MODEL_IQUE_DSI (MODEL_NINTENDO_DSI+CHINESE_SUPPORT)
#define MODEL_NINTENDO_DSI_XL 6
#define MODEL_NINTENDO_DSI_LL MODEL_NINTENDO_DSI_XL
#define MODEL_NINTENDO_3DS 8
#define MODE_DS 0
#define MODE_DSI 1
typedef union {
struct {
u8 model;
u8 flags;
u8 padding[2];
};
u32 packed;
} HwInfo;
extern bool __dsimode;
u32 getDSmodel() {
HwInfo hwinfo;
u8 fw1D;
u8 fw2F;
// reset
hwinfo.packed=0;
// read two firmware bytes we might need
readFirmware (0x1D, &fw1D, 1);
readFirmware (0x2F, &fw2F, 1);
// check if we're in DSi mode or not
if (__dsimode) {
hwinfo.flags=MODE_DSI;
hwinfo.model=MODEL_NINTENDO_DSI; // shortcut if we're in DSi mode
} else {
hwinfo.flags=MODE_DS;
hwinfo.model=MODEL_NINTENDO_DS;
}
// check if it's a DS Lite
if ((hwinfo.model==MODEL_NINTENDO_DS) && (readPowerManagement(4) & 0x40))
hwinfo.model=MODEL_NINTENDO_DS_LITE;
// check if it's a DSi
if ((hwinfo.model==MODEL_NINTENDO_DS_LITE) && (fw1D & 0x04))
hwinfo.model=MODEL_NINTENDO_DSI;
// check if it's a IQue DS
if ((hwinfo.model==MODEL_NINTENDO_DS) && (fw1D!=0xFF) && (fw1D & 0x03))
hwinfo.model=MODEL_IQUE_DS;
// check if it's a IQue DS Lite
if ((hwinfo.model==MODEL_NINTENDO_DS_LITE) && (fw1D & 0x03))
hwinfo.model=MODEL_IQUE_DS_LITE;
// NO iQUE DSi detection, yet...
// check if it's a 3DS
if ((hwinfo.model==MODEL_NINTENDO_DSI) && (fw2F>=0x1c))
hwinfo.model=MODEL_NINTENDO_3DS;
// check if it's a DSi XL
if ((hwinfo.model==MODEL_NINTENDO_DSI) && (fw2F>=0x18))
hwinfo.model=MODEL_NINTENDO_DSI_XL;
return (hwinfo.packed);
}