Single chip microcomputer -- HLK-W801 transplanted Nes simulator

Pre episode review

Single chip microcomputer HLK-W801 transplanted Nes simulator (I)
I've finished the transplantation of the program. Today, I'll try the key operation. At least I can jump and eat a mushroom

Key recognition

For the identification of keys on w801, I use an omni-directional key keyboard I used before,
The keys are collected through GPIO. In order to eliminate jitter, the mode of interrupt timer cyclic scanning is adopted. It is considered to be pressed after 8 times of continuous scanning to high level.
Method reference from blog "#51 single chip microcomputer # interrupt to realize key shaking elimination"

First define the macro

#define GPIO_UP				WM_IO_PA_01
#define GPIO_DOWN			WM_IO_PA_02
#define GPIO_LFT			WM_IO_PA_08
#define GPIO_RHT			WM_IO_PA_04
#define GPIO_START			WM_IO_PA_05
#define GPIO_A				WM_IO_PA_06
#define GPIO_B				WM_IO_PA_07

Then register GPIO,

#ifdef GPIO_UP
#ifdef GPIO_DOWN
#ifdef GPIO_B

Then define a timer to scan the keys every 2 milliseconds

void  timer_demo(void)

	u8 timer_id;
	struct tls_timer_cfg timer_cfg;
	timer_cfg.unit = TLS_TIMER_UNIT_MS;
	timer_cfg.timeout = 2;
	timer_cfg.is_repeat = 1;
	timer_cfg.callback = (tls_timer_irq_callback)demo_timer_irq;
	timer_cfg.arg = NULL;
	timer_id = tls_timer_create(&timer_cfg);
	printf("timer start\n");	


Finally, the circular scanning interrupt function is realized. Here, only one key is written as an example

static void demo_timer_irq(u8 *arg)
	#ifdef GPIO_UP
		static unsigned char keybuf_UP = 0XFF;  //Scan buffer to save the scan value for a period of time.
		u8 KEY_UP;

		keybuf_UP = (keybuf_UP<<1)|KEY_UP; //Shift the buffer one bit to the left and move the current scan value to the lowest bit.
		if(keybuf_UP == 0X00)
		{				//If the value of 8 consecutive scans is 0, that is, only the pressed state is detected within 16ms, it can be considered that the key has been pressed.
			up_key = 0; 
		else if(keybuf_UP == 0XFF)
		{				//If the value of 8 consecutive scans is 1, that is, only the pop-up state is detected within 16ms, it can be considered that the key has popped up.
			up_key = 1;

Finally, through the variable up_key, notify the simulator. The simulator circularly scans the key changes through the following functions

void InfoNES_PadState( DWORD *pdwPad1, DWORD *pdwPad2, DWORD *pdwSystem )

The three parameters are 1P,2P and on / off button respectively. The default comment is

//The handle control definition is represented by a DWORD type data, and the definitions of handle 1 and handle 2 are the same  
//      case Key_Right:
//    pdwPad1 |= (1<<7);   The seventh digit indicates right
//    break;
//  case Key_Left:
//    *pdwPad1 |= (1<<6);  The sixth digit indicates left
//    break;
//  case Key_Down:
//    *pdwPad1 |= (1<<5); The fifth digit indicates next
//    break;
//  case Key_Up:
//    *pdwPad1 |= (1<<4); The fourth digit means up
//    break;
//  case Key_S:
//    *pdwPad1 |= (1<<3); The third digit indicates Start
//    break;
//  case Key_A:
//    *pdwPad1 |= (1<<2);  A key
//    break;
//  case Key_Z: 
//    *pdwPad1 |= (1<<1);  Z key
//    break;
//  case Key_X:
//    *pdwPad1 |= (1<<0);  X key

Here is the above key as an example

#define PAD_JOY_UP		0x10
    *pdwPad1 = 0;
#ifdef GPIO_UP
		*pdwPad1 |= PAD_JOY_UP;

Super Mary this game, add the left and right start and A key, you can play it without acceleration. After adding, show the effect

Although it is too laggy, and the color is not right, it is the first step.

Color problem

It is estimated that when writing SPI, the color of the point is related to the byte order. The guess is correct. After reversing the order, the color is much more pure

void ILI9341_DrawLineOne(u16 y,u16* data)
	int i=0;
	u16* dat=data;
	ILI9341_Address_Set(0,y,240,y);//Set cursor position 
	GPIO_DATA();//Write data
		uint8_t data[2];
		data[0] = (*dat)>>8;
		data[1] = (*dat);
		tls_spi_write((uint8_t *)data,2);

But the subsequent rate is slower... Because every time you draw a point, you need to calculate and reverse the data, and then write the SPI.
But I got another idea right away,
If it wants to display AB;
I made a mistake and displayed AB as BA;
So when I ask nes to calculate the point, I also make a mistake. If it wants AB, I'll give it BA, add error to error
So when I draw BA, I will draw AB, so

The purpose of drawing AB is achieved!!!

This is called negative positive!!!

The results really showed normal.
The modification method is to change SPI back to the original and write a line directly

void ILI9341_DrawLineOne(u16 y,u16* data)
	int i=0;
	ILI9341_Address_Set(0,y,240,y);//Set cursor position 
	GPIO_DATA();//Write data
	tls_spi_write((uint8_t *)data,480);

Then switch the high and low positions of the palette

/*  Palette data                                                     */
WORD NesPalette[64]={
#if 0

I'm a genius

Refresh rate

This is still under study

Concluding remarks

On the last day of work years ago, I didn't have any desire for a holiday. I heard that the leader and pressed the North nose divorced. Maybe someone persuaded one of them not to divorce and keep it for the new year? I hope you don't have to go to the hot search because of your family property. You've seen enough of these people.

Keywords: Single-Chip Microcomputer MCU RTOS

Added by moiseszaragoza on Fri, 28 Jan 2022 10:54:25 +0200