05 파워 컨트롤(Power Control)

원문 : http://kkamagui.springnote.com/pages/411216

 

들어가기 전에...

 

0. 시작하면서...

 NDS는 LCD, 사운드, Graphic 엔진 등 여러가지 장비를 가지고 있다. 이 장비는 파워 컨트롤 레지스터에 특정 값을 입력함으로써 조절할 수 있으며 ARM9과 ARM7 별로 컨트롤 할 수 있는 장비가 다르다.

http://nocash.emubase.de/gbatek.htm#dspowermanagement 를 참조하면 Power Control에 대한 자세한 정보를 얻을 수 있는데, 아래와 같다.

 

1. Port I/O

1.1 Port And Bit

 먼저 살펴볼 부분은 Port I/O를 통해서 접근할 수 있는 장비에 대한 부분이다.

The DS contains several Power Managment functions, some accessed via I/O ports, some accessed via SPI bus (described later on below).

4000304h - POWCNT1 - NDS9 - Graphics Power Control Register (R/W)

0     Enable Flag for both LCDs (0=Disable) (Prohibited, see notes)
  1     2D Graphics Engine A      (0=Disable) (Ports 008h-05Fh, Pal 5000000h)
  2     3D Rendering Engine       (0=Disable) (Ports 320h-3FFh)
  3     3D Geometry Engine        (0=Disable) (Ports 400h-6FFh)
  4-8   Not used
  9     2D Graphics Engine B      (0=Disable) (Ports 1008h-105Fh, Pal 5000400h)
  10-14 Not used
  15    Display Swap (0=Send Display A to Lower Screen, 1=To Upper Screen)
Use SwapBuffers command once after enabling Rendering/Geometry Engine.
Improper use of Bit0 may damage the hardware?
When disabled, corresponding Ports become Read-only, corresponding (palette-) memory becomes read-only-zero-filled.

4000304h - POWCNT2 - NDS7 - Sound/Wifi Power Control Register (R/W)
Bit   Expl.
  0     Sound Speakers (0=Disable, 1=Enable) (Initial setting = 1)
  1     Wifi           (0=Disable, 1=Enable) (Initial setting = 0)
  2-31  Not used
Note: Bit0 disables the internal Speaker only, headphones are not disabled.
Bit1 disables Port 4000206h, and Ports 4800000h-480FFFFh.

4000206h - NDS7 - WIFIWAITCNT - Wifi Waitstate Control
Bit   Expl.
  0-2   Wifi WS0 Control (0-7) (Ports 4800000h-4807FFFh)
  3-5   Wifi WS1 Control (0-7) (Ports 4808000h-480FFFFh)
  4-15  Not used (zero)
This register is initialized by firmware on power-up, don't change.
Note: WIFIWAITCNT can be accessed only when enabled in POWCNT2.

4000301h - NDS7 - HALTCNT - Low Power Mode Control (R/W)
In Halt mode, the CPU is paused as long as (IE AND IF)=0.
In Sleep mode, most of the hardware including sound and video are paused, this very-low-power mode could be used much like a screensaver.
Bit   Expl.
  0-5   Not used (zero)
  6-7   Power Down Mode  (0=No function, 1=Enter GBA Mode, 2=Halt, 3=Sleep)
The HALTCNT register should not be accessed directly. Instead, the BIOS Halt, Sleep, CustomHalt, IntrWait, or VBlankIntrWait SWI functions should be used.
BIOS Halt Functions
ARM CP15 System Control Coprocessor
The NDS9 does not have a HALTCNT register, instead, the Halt function uses the co-processor opcode "mcr p15,0,r0,c7,c0,4" - this opcode locks up if interrupts are disabled via IME=0 (unlike NDS7 HALTCNT method which doesn't check IME).

4000300h - NDS7/NDS9 - POSTFLG - BYTE - Post Boot Flag (R/W)
The NDS7 and NDS9 post boot flags are usually set upon BIOS/Firmware boot completion, once when set the reset vector is redirected to the debug handler of Nintendo's hardware debugger. That allows the NDS7 debugger to capture accidental jumps to address 0, that appears to be a common problem with HLL-programmers, asm-coders know that (and why) they should not jump to 0.
Bit   Expl.
  0     Post Boot Flag (0=Boot in progress, 1=Boot completed)
  1     NDS7: Not used (always zero), NDS9: Bit1 is read-writeable
  2-7   Not used (always zero)
There are some write-restrictions: The NDS7 register can be written to only from code executed in BIOS. Bit0 of both NDS7 and NDS9 registers cannot be cleared (except by Reset) once when it is set.

 ARM9과 ARM7에서 접근할 수 있는 부분이 위와 같이 다르고 해당 비트만 0/1을 바꿔주면 간단히 제어할 수 있다는 것을 알 수 있다.

1.2 libnds 분석

 Devkit Pro의 libnds 및의 Source 폴더에 가면 실제 구현한 소스와 헤더를 볼 수 있다. Port I/O 관련 파워 관리 부분은 system.h 파일에 있으므로  한번 살펴보자.

 Port I/O 이므로 파워를 컨트롤 할 수 있는 포트 번호를 알아야 하는데 system.h 파일에 아래와 같이 정의 되어있고 02 NDS Spec 에서도 찾아볼 수 있다.

  1. #define REG_POWERCNT *(vu16*)0x4000304

  위의 정의를 보니 16bit의 크기를 가지는 것 같다. ARM9과 ARM7에 대해서 정의해 놓은 값도 같이 보자.

  1. #define POWER_LCD   BIT(0)
    #define POWER_2D_A   BIT(1)
    #define POWER_MATRIX  BIT(2)
    #define POWER_3D_CORE  BIT(3)
    #define POWER_2D_B   BIT(9)
    #define POWER_SWAP_LCDS  BIT(15)
  2. //! Enables power to all hardware required for 2D video.
    #define POWER_ALL_2D     (POWER_LCD |POWER_2D_A |POWER_2D_B)
  3. //! Enables power to all hardware required for 3D video.
    #define POWER_ALL   (POWER_ALL_2D | POWER_3D_CORE | POWER_MATRIX)

 위에서 파워 조작 레지스터의 비트값을 그대로 매크로로 만들었음을 알 수 있다. BIT()는 해당 비트를 1로 설정해 주는 역할을 하는 간단한 매크로이다.

 

1.3 사용 예제

 매크로를 사용하여 LCD를 키고 그래픽을 표시하려면 아래와 같이 사용하면 된다.

  1. REG_POWERCNT |= POWER_ALL_2D;
  2. powerON( POWER_ALL_2D ); <== 위의 코드와 비슷한 역할을 하는 매크로다.

 만약 위처럼 Engine을 Enable 하지 않고 그냥 LCD만 ON(bit0)만 하면 어떻게 될까? 실제로 해보면 상단 LCD에는 흰색이, 하단 LCD에는 검은색만 표시되고 화면에 아무것도 그려지지 않는다.

 엔진 A를 Enable 시키면? 하단 LCD에 그림이 표시되며, 엔진 B를 Enable 시키면? 상단 LCD가 표시된다. 이때 Swap을 Enable 시키면 상/하단이 바뀌어서 나오게 된다.

  I/O 포트를 이용해서 제어하는 방식은 위와 같이 하면 끝이다.

 

2. SPI

2.1 Index And Registers

 아래는 SPI를 사용해서 접근해야 하는 부분이다.

Power Management Device
The Power Management Device is accessed via SPI bus,
DS Serial Peripheral Interface Bus (SPI)
To access the device, write the Index Register, then read or write the data register, and release the chipselect line when finished.

Index Register

Bit0-1 Register Select          (0..3)
  Bit2-6 Not used
  Bit7   Register Direction       (0=Write, 1=Read)
Register 0 - Powermanagement Control (R/W)
Bit0   Sound Amplifier          (0=Disable, 1=Enable)
         (When disabled, sound becomes very silent, but it is still audible)
  Bit1   Sound related?           (0=Disable, 1=Enable)
  Bit2   Lower Backlight          (0=Disable, 1=Enable)
  Bit3   Upper Backlight          (0=Disable, 1=Enable)
  Bit4   Power LED Blink Enable   (0=Always ON, 1=Blinking OFF/ON)
  Bit5   Power LED Blink Speed    (0=Slow, 1=Fast) (only if Blink enabled)
  Bit6   DS System Power          (0=Normal, 1=Shut Down)
  Bit7   Not used
Register 1 - Battery Status (R)
Bit0   Battery Power LED Status (0=Power Good/Green, 1=Power Low/Red)
  Bit1-7 Not used
Register 2 - Microphone Amplifier Control (R/W)
Bit0   Amplifier                (0=Disable, 1=Enable)
  Bit1-7 Not used
Register 3 - Microphone Amplifier Gain Control (R/W)
Bit0-1 Gain                     (0..3=Gain 20, 40, 80, 160)
  Bit2-7 Not used

Backlight Dimming / Backlight caused Shut-Down(s)
The above bits are essentially used to switch Backlights on or off. However, there a number of strange effects. Backlight dimming is possible by pulse width modulation, ie. by using a timer interrupt to issue pulse widths of N% ON, and 100-N% OFF. Too long pulses are certainly resulting in flickering. Too short pulses are ignored, the backlights will remain OFF, even if the ON and OFF pulses are having the same length. Much too short pulses cause the power supply to shut-down; after changing the backlight state, further changes must not occur within the next (circa) 2500 clock cycles. The mainboard can be operated without screens & backlights connected, however, if so, the power supply will shut-down as soon as backlights are enabled.

Memory Power Down Functions
DS Main Memory Control
DS Firmware Serial Flash Memory

 

2.2 SPI(Serial Peripheral Interface Bus)

 SPI는 아래의 I/O 포트로 제어해야 한다.

Serial Peripheral Interface Bus
SPI Bus is a 4-wire (Data In, Data Out, Clock, and Chipselect) serial bus.
The NDS supports the following SPI devices (each with its own chipselect).
DS Firmware Serial Flash Memory
DS Touch Screen Controller (TSC)
DS Power Management

40001C0h - SPICNT - NDS7 - SPI Bus Control/Status Register

0-1   Baudrate (0=4MHz/Firmware, 1=2MHz/Touchscr, 2=1MHz/Powerman., 3=512KHz)
  2-6   Not used            (Zero)
  7     Busy Flag           (0=Ready, 1=Busy) (presumably Read-only)
  8-9   Device Select       (0=Powerman., 1=Firmware, 2=Touchscr, 3=Reserved)
  10    Transfer Size       (0=8bit/Normal, 1=16bit/Bugged)
  11    Chipselect Hold     (0=Deselect after transfer, 1=Keep selected)
  12-13 Not used            (Zero)
  14    Interrupt Request   (0=Disable, 1=Enable)
  15    SPI Bus Enable      (0=Disable, 1=Enable)
The "Hold" flag should be cleared BEFORE transferring the LAST data unit, the chipselect will be then automatically cleared after the transfer, the program should issue a WaitByLoop(3) manually AFTER the LAST transfer.

40001C2h - SPIDATA - NDS7 - SPI Bus Data/Strobe Register (R/W)
The SPI transfer is started on writing to this register, so one must <write> a dummy value (should be zero) even when intending to <read> from SPI bus.
0-7   Data
  8-15  Not used (always zero, even in bugged-16bit mode)
During transfer, the Busy flag in SPICNT is set, and the written SPIDATA value is transferred to the device (via output line), simultaneously data is received (via input line). Upon transfer completion, the Busy flag goes off (with optional IRQ), and the received value can be then read from SPIDATA, if desired.

Notes/Glitches
SPICNT Bits 12,13 appear to be unused (always zero), although the BIOS (attempts to) set Bit13=1, and Bit12=Bit11 when accessing the firmware.
The SPIDATA register is restricted to 8bit, so that only each second byte will appear in the register when attemting to use the bugged 16bit mode.

Cartridge Backup Auxiliar SPI Bus
The NDS Cartridge Slot uses a separate SPI bus (with other I/O Ports), see
DS Cartridge Backup

 Port I/O를 쓰지않고 SPI를 통해서 접근해야하는 부분들은 위와 같다. SPI는 ARM7에만 연결되어있으므로 ARM7을 통해서 접근해야 한다.

 

Power Management Device
The Power Management Device is accessed via SPI bus,
DS Serial Peripheral Interface Bus (SPI)
To access the device, write the Index Register, then read or write the data register, and release the chipselect line when finished.

Index Register

Bit0-1 Register Select          (0..3)
  Bit2-6 Not used
  Bit7   Register Direction       (0=Write, 1=Read)
Register 0 - Powermanagement Control (R/W)
Bit0   Sound Amplifier          (0=Disable, 1=Enable)
         (When disabled, sound becomes very silent, but it is still audible)
  Bit1   Sound related?           (0=Disable, 1=Enable)
  Bit2   Lower Backlight          (0=Disable, 1=Enable)
  Bit3   Upper Backlight          (0=Disable, 1=Enable)

Bit4 Power LED Blink Enable (0=Always ON, 1=Blinking OFF/ON) Bit5 Power LED Blink Speed (0=Slow, 1=Fast) (only if Blink enabled) Bit6 DS System Power (0=Normal, 1=Shut Down) Bit7 Not used
Register 1 - Battery Status (R)
Bit0   Battery Power LED Status (0=Power Good/Green, 1=Power Low/Red)
  Bit1-7 Not used
Register 2 - Microphone Amplifier Control (R/W)
Bit0   Amplifier                (0=Disable, 1=Enable)
  Bit1-7 Not used
Register 3 - Microphone Amplifier Gain Control (R/W)
Bit0-1 Gain                     (0..3=Gain 20, 40, 80, 160)
  Bit2-7 Not used

Backlight Dimming / Backlight caused Shut-Down(s)
The above bits are essentially used to switch Backlights on or off. However, there a number of strange effects. Backlight dimming is possible by pulse width modulation, ie. by using a timer interrupt to issue pulse widths of N% ON, and 100-N% OFF. Too long pulses are certainly resulting in flickering. Too short pulses are ignored, the backlights will remain OFF, even if the ON and OFF pulses are having the same length. Much too short pulses cause the power supply to shut-down; after changing the backlight state, further changes must not occur within the next (circa) 2500 clock cycles. The mainboard can be operated without screens & backlights connected, however, if so, the power supply will shut-down as soon as backlights are enabled.

 Power Management Register는 재미있는 항목들을 가지고 있다. DS를 닫았을 때, 파워 LED가 깜빡이게 하는 기능을 포함해서 전체 파워를 끄는기능, 깜빡이는 속도를 조절하는 기능 등등을 가지고 있다. 잘 활용하면 쉽게 사용할 수 있을 것 같다. SPI를 통해 사용해야 하므로 07 Serial Peripheral Interface(SPI) 부분을 참고하도록 하자.

 

2.3 libnds 분석

 여기다 분석해서 글 적기

 

2.4 사용 예제

 아래의 예제는 SPI를 사용하는 예제로써 Register 0의 값을 읽어 전원 관련 부분 LED를 Blink하는 소스이다.

  1. #include <nds.h>
  2. /**
        LED를 Slow or Fast로 깜빡이게 하거나 계속 켜져있도록 한다.
            SPI를 통해 보낸다.
    */
    void SetLEDBlinkMode( bool bBlinkEnable, bool bSlow )
    {
        unsigned char ucData;
       
        ucData = 0;
       
        SerialWaitBusy();
        // SPI를 설정한다.
        REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz | SPI_DEVICE_POWER | SPI_CONTINUOUS;
        // Read Mode로 설정하고 Register 0을 선택한다.
        REG_SPIDATA = 0x80;
  3.     SerialWaitBusy();
        // 마지막 더미 데이터를 보내서 데이터를 바로 읽도록 한다.
        REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz | SPI_DEVICE_POWER;
        REG_SPIDATA = 0x00;
       
        // Register 0에서 데이터를 읽는다.
        SerialWaitBusy();
        ucData = REG_SPIDATA;
  4.     // 만약 깜빡임 모드가 아니면 계속 켜져있도록 설정한다.
        if( bBlinkEnable == false )
        {
            ucData &= ~( BIT( 4 ) );
        }
        // 깜빡임 모드이면 Slow/Fast에 따라서
        else
        {
            ucData |= BIT( 4 );
            if( bSlow == true )
            {
                ucData &= ~( BIT( 5 ) );
            }
            else
            {
                ucData |= BIT( 5 );
            }
        }
  5.     SerialWaitBusy();
        // SPI를 설정한다.
        REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz | SPI_DEVICE_POWER | SPI_CONTINUOUS;
       // Write Mode로 설정하고 Register 0을 선택한다.
        REG_SPIDATA = 0x00;
       
        // Register 0에 데이터를 보낸다.
        SerialWaitBusy();
        REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz | SPI_DEVICE_POWER;
        REG_SPIDATA = ucData;
    }

 위의 소스를 보면 상단의 파란색 블럭은 Register 0에서 값을 읽는 부분이고 하단의 파란색 블럭은 Register 0에 값을 쓰는 부분임을 알 수 있다. 소스에서 나타난 흐름 같은 부분은 07 Serial Peripheral Interface(SPI) 문서를 보면 된다.

 

3. 마치며...

 여기다 마무리 하기.

 

 

 

이 글은 스프링노트에서 작성되었습니다.

+ Recent posts