Wifi /
Operation

Menu

Getting Started

System Information

Misc

Initialization Sequence

These events must be done somewhat in sequence. There is some flexibility as to how they can be ordered but it's best to follow this order:

 
Init Sequence:
  // Enable power to the wifi system
  POWERCNT |= 2;

  // unclear if this is necessary, or exactly what it does.
  *((volatile u16 *)0x04000206) = 0x30; 

  // Set Mac address
  copy 6 bytes from flash[0x36] to mac address at 0x04800018

  // Disable interrupts from wireless sources
  W_IE = 0;

Wake up the wireless system:
   [u16 0x04800036] = 0
   delay 8 ms
   [u16 0x04800168] = 0
   temp = BB_Read(1);
   BB_Write(1,temp&0x7F);
   BB_Write(1,temp);
   delay 30 ms

   // same as "Init the RF system", below.
   // this or the other one is probably not necessary.
   RF_Init

 Init the Mac system:
   // Set the following registers (offset from 0x04800000) to the
   // specified values:
   reg[0x04] = 0
   reg[0x08] = 0
   reg[0x0A] = 0
   reg[0x12] = 0
   reg[0x10] = 0xffff
   reg[0x254]= 0
   reg[0xB4] = 0xffff
   reg[0x80] = 0
   reg[0x2A] = 0
   reg[0x28] = 0
   reg[0xE8] = 0
   reg[0xEA] = 0
   reg[0xEE] = 1
   reg[0xEC] = 0x3F03
   reg[0x1A2]= 1
   reg[0x1A0]= 0
   reg[0x110]= 0x0800
   reg[0xBC] = 1
   reg[0xD4] = 3
   reg[0xD8] = 4
   reg[0xDA] = 0x0602
   reg[0x76] = 0
 Init the RF system:
   // write 16bit values from flash (starting at offset 0x44) to
   // the following list of registers (offset from 0x04800000) -
   // the actual assignments are also listed here for reference.
   list: 0x146, 0x148, 0x14A, 0x14C, 0x120, 0x122, 0x154, 0x144,
         0x130, 0x132, 0x140, 0x142, 0x038, 0x124, 0x128, 0x150
   Actual assignments (based on present firmware dumps):
   reg[0x146] = 0x0002
   reg[0x148] = 0x0017
   reg[0x14A] = 0x0026
   reg[0x14C] = 0x1818
   reg[0x120] = 0x0048
   reg[0x122] = 0x4840
   reg[0x154] = 0x0058
   reg[0x144] = 0x0042
   reg[0x130] = 0x0140
   reg[0x132] = 0x8064
   reg[0x140] = 0xE0E0
   reg[0x142] = 0x2443
   reg[0x038] = 0x000E
   reg[0x124] = 0x0032
   reg[0x128] = 0x01F4
   reg[0x150] = 0x0101
Note: DO NOT USE THESE VALUES, READ THE CORRECT ONES FROM FIRMWARE 
 

   numentries = flash byte at 0x42 (=0x0C == 12)
   numbits = flash byte at 0x41
   numbytes = (numbits+7)/8;

   // specifies number of bits per transfer
   reg[0x184] = ((numbits<<1) & 0x0100) | (numbits&0x7F) -- W_RFSIOCNT

   if flash byte 0x40 == 3 { -- doesn't in current firmware...
     // not going to go over this one, as it's not the case in present firmware.
     for(i=0;i<numentries;i++) RF_Write(0x50000 | (i<<8) | flash byte at 0xCE+i);  
   } else {
     for(i=0;i<numentries;i++) RF_Write(numbytes flash bytes, starting at 0xCE + i*numbytes);
   }

   // For the second case, which is the currently used one,
   // the following values are written to RF_Write:
   RF_Write 0x00C007
   RF_Write 0x129C03
   RF_Write 0x141728
   RF_Write 0x1AE8BA
   RF_Write 0x1D456F
   RF_Write 0x23FFFA
   RF_Write 0x241D30
   RF_Write 0x280001
   RF_Write 0x2C0000
   RF_Write 0x069C03
   RF_Write 0x080022
   RF_Write 0x0DFF6F		
// really odd values, unclear exactly what they mean but it's likely they're
// initializing a PLL or something with various frequencies or options.
Note: DO NOT USE THESE VALUES, READ THE CORRECT ONES FROM FIRMWARE 
 

Init the BaseBand System:  -- and you thought the RF init was bad?
   // The baseband init is rather simple, just read in 105 values and
   // write them to the baseband. simple, eh? :)
   // routine goes like this:
   reg(0x160) = 0x0100
   for(i=0;i<0x69;i++) BB_Write( i, flash byte 0x64+i );
   For your convenience (or torture), all 105 values are listed here:
   BB_Write   0, 0x6D       BB_Write   1, 0x9E       
   BB_Write   2, 0x40       BB_Write   3, 0x05
   BB_Write   4, 0x1B       BB_Write   5, 0x6C
   BB_Write   6, 0x48       BB_Write   7, 0x80
   BB_Write   8, 0x38       BB_Write   9, 0x00
   BB_Write  10, 0x35       BB_Write  11, 0x07
   BB_Write  12, 0x00       BB_Write  13, 0x00
   BB_Write  14, 0x00       BB_Write  15, 0x00
   BB_Write  16, 0x00       BB_Write  17, 0x00
   BB_Write  18, 0x00       BB_Write  19, 0x00
   BB_Write  20, 0xB0       BB_Write  21, 0x00
   BB_Write  22, 0x04       BB_Write  23, 0x01
   BB_Write  24, 0xD8       BB_Write  25, 0xFF
   BB_Write  26, 0xFF       BB_Write  27, 0xC7
   BB_Write  28, 0xBB       BB_Write  29, 0x01
   BB_Write  30, 0xB6       BB_Write  31, 0x7F
   BB_Write  32, 0x5A       BB_Write  33, 0x01
   BB_Write  34, 0x3F       BB_Write  35, 0x01
   BB_Write  36, 0x3F       BB_Write  37, 0x36
   BB_Write  38, 0x36       BB_Write  39, 0x00
   BB_Write  40, 0x78       BB_Write  41, 0x28
   BB_Write  42, 0x55       BB_Write  43, 0x08
   BB_Write  44, 0x28       BB_Write  45, 0x16
   BB_Write  46, 0x00       BB_Write  47, 0x01
   BB_Write  48, 0x0E       BB_Write  49, 0x20
   BB_Write  50, 0x02       BB_Write  51, 0x98
   BB_Write  52, 0x98       BB_Write  53, 0x1F
   BB_Write  54, 0x0A       BB_Write  55, 0x08
   BB_Write  56, 0x04       BB_Write  57, 0x01
   BB_Write  58, 0x00       BB_Write  59, 0x00
   BB_Write  60, 0x00       BB_Write  61, 0xFF
   BB_Write  62, 0xFF       BB_Write  63, 0xFE
   BB_Write  64, 0xFE       BB_Write  65, 0xFE
   BB_Write  66, 0xFE       BB_Write  67, 0xFC
   BB_Write  68, 0xFC       BB_Write  69, 0xFA
   BB_Write  70, 0xFA       BB_Write  71, 0xFA
   BB_Write  72, 0xFA       BB_Write  73, 0xFA
   BB_Write  74, 0xF8       BB_Write  75, 0xF8
   BB_Write  76, 0xF6       BB_Write  77, 0xA5
   BB_Write  78, 0x12       BB_Write  79, 0x14
   BB_Write  80, 0x12       BB_Write  81, 0x41
   BB_Write  82, 0x23       BB_Write  83, 0x03
   BB_Write  84, 0x04       BB_Write  85, 0x70
   BB_Write  86, 0x35       BB_Write  87, 0x0E
   BB_Write  86, 0x16       BB_Write  89, 0x16
   BB_Write  90, 0x00       BB_Write  91, 0x00
   BB_Write  92, 0x06       BB_Write  93, 0x01
   BB_Write  94, 0xFF       BB_Write  95, 0xFE
   BB_Write  98, 0xFF       BB_Write  97, 0xFF
   BB_Write  98, 0x00       BB_Write  99, 0x0E
   BB_Write 100, 0x13       BB_Write 101, 0x00
   BB_Write 102, 0x00       BB_Write 103, 0x28
   BB_Write 104, 0x1C 
Note: DO NOT USE THESE VALUES, READ THE CORRECT ONES FROM FIRMWARE 
 

// Set Mac address
copy 6 bytes from flash[0x36] to mac address at 0x04800018

// now just set some default varibles
 W_RETRLIMIT = 7

 Set channel (see section on changing channels)
 Set Mode 2 -- sets bottom 3 bits of W_MODE_WEP to 2
 Set Wep Mode / key -- Wep mode is bits 3..5 of W_MODE_WEP

 BB_Write 0x13, 0x00
 BB_Write 0x35, 0x1F

// To further init wifi to the point that you can properly send and
// receive data, there are some more variables that need to be set.
  reg[0x032] = 0x8000 -- (clear error flag?)
  reg[0x134] = 0xFFFF
  reg[0x028] = 0      -- clear W_AID value
  reg[0x02A] = 0
  reg[0x0E8] = 1      -- enable microsecond counter
  reg[0x038] = 0      
  reg[0x020] = 0      -- clear BSSID
  reg[0x022] = 0
  reg[0x024] = 0

TX prepare:
  reg[0x0AE] = 0x000D -- flush all pending transmits

RX prepare:
  reg[0x030] = 0x8000

  // these are just my default values, you can set basicly whatever you want.
  reg[0x050] = 0x4C00 -- RX Fifo begin
  reg[0x052] = 0x5F60 -- RX Fifo end (length = 4960 bytes)
  reg[0x056] = 0x0600 -- fifo begin latch address, 0xC00/2 = 0x600
  reg[0x05A] = 0x0600 -- fifo end, same as begin at start.
  reg[0x062] = 0x5F5E -- last element of fifo (unclear if this is necessary)
  reg[0x030] = 0x8001 -- latch new fifo values for hardware use

  reg[0x030] = 0x8000 -- enable receive
  W_IF=0xFFFF         -- clear interrupt flags
  W_IE=(whatever)     -- set enabled interrupts
  reg[0x1AE] = 0x1FFF
  reg[0x1AA] = 0

// set this to 0x581 when you successfully connect to an
// access point and fill W_BSSID with a mac address for it. 
  reg[0x0D0] = 0x181  // (W_RXFILTER)
  reg[0x0E0] = 0x000B
  reg[0x008] = 0
  reg[0x00A] = 0
  reg[0x004] = 1      -- hardware mode
  reg[0x0E8] = 1
  reg[0x0EA] = 1
  reg[0x048] = 0
  reg[0x038] &= ~2
  reg[0x048] = 0
  reg[0x0AE] = 2
  reg[0x03C] |= 2
  reg[0x0AC] = 0xFFFF

And, that's it. after all that the DS should be happy to send and receive packets. It's very possible there are unnecessary register sets in here, but this pseudocode is based very closely on my current working codebase, and it should work. I just haven't had the time to weed out all of the unnecessary parts, and test to verify they were indeed unnecessary.

Please keep in mind that this is very preliminary information, if you find bugs or can't make it work, please let me know.

Reading Firmware

Check out Firmware for more information (code at the bottom).

RF / Baseband communications

RF_Write(data)

   while(W_RFSIOBUSY&1);
  W_RFSIODATA1=(data & 0xFFFF);
  W_RFSIODATA2=(data >> 16);
  while(W_RFSIOBUSY&1);

BB_Write(address,data)

   counter=10000;
  while((W_BBSIOBUSY&1) && (--counter));
  if(!counter) return -1;
  W_BBSIOWRITE=data;
  W_BBSIOCNT=address | 0x5000;
  counter=10000;
  while((W_BBSIOBUSY&1) && (--counter));
  return 0;

BB_Read(address)

   while(W_BBSIOBUSY&1);
  if(!counter) return -1;
  W_BBSIOCNT=address | 0x6000;
  while(W_BBSIOBUSY&1);
  return W_BBSIOREAD;

Wifi Transmit Procedure

To transmit data via wifi (Assuming you've already initialized wifi and changed channels to the channel you want):

  1. Copy the TX Header followed by the 802.11 packet to send anywhere it will fit in MAC memory (halfword-aligned)
  2. Take the offset from start of MAC memory that you put the packet, divide it by 2, and or with 0x8000 - store this in one of the W_TXLOC registers
  3. Store the bit associated with the W_TXLOC register you used into W_TXCNT - this will send the packet.
  4. You can then read the result data in W_TXSTAT when the TX is over (you can tell either by polling or interrupt) to find out how many retries were used, and if the packet was ACK'd

Of course, this is just the simplest approach, you can be a lot more clever about it.

TX Header

The TX header is a structure needed by the wifi hardware, it contains important information such as the length of the packet being sent and the rate at which to send (possibly other things too). The TX header is always 12 bytes, it immediately precedes the data to be sent, and should be put at the location that will be given to the register activating a transmission. The TX header takes the following form: (entries are halfwords)

 Offset Description
 +0    Unknown (used by hardware)
 +2    Unknown (used by hardware)
 +4    Unknown (used by hardware)
 +6    Unknown (used by hardware)
 +8    Transmit rate (speed in megabits multiplied by 10 - 1.0Mbit is 0x0A, 2.0Mbit is 0x14)
 +10   Transmit length (bytes) transmits the data at +12 through +12+length-1 inclusive.

Important note! TX length includes the length of a 4-byte "FCS" (checksum) for the packet. The hardware generates the FCS for you, but you still must include it in the packet length. Also note that if the 802.11 WEP enabled bit is set in the header, the packet will be automatically encrypted via the wep algorithm - however, the software is responsible for providing the 4-byte IV block with the WEP key ID and the 24bit IV value.

Wifi Receive Procedure

To receive data via wifi, you either need to handle the wifi received data interrupt, or you need to poll W_RXHWWRITECSR - whenever it is != W_RXREADCSR, there is a new packet. When there is a new packet, take the following approach:

  1. Calculate the length of the new packet (read "received frame length" which is +8 bytes from the start of the packet) - total frame length is (12 + received frame length) padded to a multiple of 4 bytes.
  2. Read the data out of the RX FIFO area (keep in mind it's a circular buffer and you may have to wrap around the end of the buffer)
  3. Set the value of W_RXREADCSR to the location of the next packet (add the length of the packet, and wrap around if necessary)

Keep in mind, W_RXREADCSR and W_RXHWWRITECSR must be multiplied by 2 to get a byte offset from the start of MAC memory

RX Header

The RX header is an informational structure that provides needed information about a received packet. It is written right before the received packet data in the rx circular buffer. The RX header is always 12 bytes. The RX header takes the following form: (entries are halfwords)

 Offset Description
 +0    Unknown (used by hardware)
 +2    Unknown (used by hardware)
 +4    Unknown (used by hardware)
 +6    Unknown (used by hardware)
 +8    Received frame length (bytes)
 +10   bottom 8 bits are RSSI (not 100% sure)

Important Note: Received frame lengths are always multiples of 4 bytes. While the actual header length + received frame length may be less, when incrementing the read cursor you must pad the length to a multiple of 4 bytes

Wifi Change Channels Procedure

You can set the channel to any channel number between 1 and 13 (inclusive) on the DS hardware. here's some pseudocode to do it:

 read 3 bytes of flash starting at (0xF2+(channel-1)*6) to a temporary value
call RF_Write with the 3 bytes you just read (as a 0-padded long value)
read 3 bytes of flash starting at (0xF5+(channel-1)*6) to a temporary value
again, call RF_Write with the 3 bytes you just read (as a 0-padded long value)
delay a few milliseconds
call BB_Write with parameters 0x1E, and the byte in flash at 0x146+(channel-1)

Congrats, you are now ready to transmit/receive on whatever channel you picked.

Recent Changes (All) | Edit SideBar

Page last modified on October 29, 2005, at 05:37 PM
Edit Page | Page History
Everything done on this project is for the sole purpose of writing interoperable software under Sect. 1201 (f) Reverse Engineering exception of the DMCA.
This site is not affiliated with Nintendo in any manner. Nintendo DS © 2004 Nintendo. TM and ® are trademarks of Nintendo.
Powered by PmWiki