diff --git a/MCUME_teensy41/bin/wheretofind.txt b/MCUME_teensy41/bin/wheretofind.txt new file mode 100755 index 0000000..f135e0f --- /dev/null +++ b/MCUME_teensy41/bin/wheretofind.txt @@ -0,0 +1 @@ +Go to T-COMPUTER GitHub to find T-COMPUTER HEX precompiled binaries... \ No newline at end of file diff --git a/MCUME_teensy41/howtocompile.txt b/MCUME_teensy41/howtocompile.txt index 58fe020..7ea322f 100755 --- a/MCUME_teensy41/howtocompile.txt +++ b/MCUME_teensy41/howtocompile.txt @@ -1,4 +1,10 @@ -HEX can be found in bin directory. +Select target board in platform_config.h file. +Default is TEECOMPUTER. +Comment out for MCUMEVGA (see wiring in schematics subdirectory) +Soldering the PSRAM (PT8211) below the Teensy4.1 is mandatory!!!! All compiled with Arduino 1.8.19 + Teensyduino 1.56 -Except UAE TEECOMPUTER for TFT that needs Arduino 1.8.13 + 1.54 +Chose optimize:smallest code and USB keyboard layout if needed. + +Default CPU speed 600MZ except for TeenyUAE and TeensySNES that need 816MHz. +TeensySNES has USB disabled! diff --git a/MCUME_teensy41/teecomputeraudiovideotest/AudioPlaySystem.cpp b/MCUME_teensy41/teecomputeraudiovideotest/AudioPlaySystem.cpp index c35d716..85da04d 100644 --- a/MCUME_teensy41/teecomputeraudiovideotest/AudioPlaySystem.cpp +++ b/MCUME_teensy41/teecomputeraudiovideotest/AudioPlaySystem.cpp @@ -1,4 +1,4 @@ -#include "platform_config.h" +#include "emuapi.h" #ifdef HAS_SND @@ -176,7 +176,6 @@ void AudioPlaySystem::step(void) { } -#ifndef HAS_T4_VGA /******************************************************************* Experimental I2S interrupt based sound driver for PCM51xx !!! *******************************************************************/ @@ -263,7 +262,57 @@ FLASHMEM static void config_sai1() I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE ;//<-- not using DMA */; } +FLASHMEM static void config_pt8211() +{ + CCM_CCGR5 |= CCM_CCGR5_SAI1(CCM_CCGR_ON); + double fs = AUDIO_SAMPLE_RATE_EXACT; + // PLL between 27*24 = 648MHz und 54*24=1296MHz + int n1 = 4; //SAI prescaler 4 => (n1*n2) = multiple of 4 + int n2 = 1 + (24000000 * 27) / (fs * 256 * n1); + double C = (fs * 256 * n1 * n2) / 24000000; + int c0 = C; + int c2 = 10000; + int c1 = C * c2 - (c0 * c2); + set_audioClock(c0, c1, c2, true); + // clear SAI1_CLK register locations + CCM_CSCMR1 = (CCM_CSCMR1 & ~(CCM_CSCMR1_SAI1_CLK_SEL_MASK)) + | CCM_CSCMR1_SAI1_CLK_SEL(2); // &0x03 // (0,1,2): PLL3PFD0, PLL5, PLL4 + + //n1 = n1 / 2; //Double Speed for TDM + + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_SAI1_CLK_PRED_MASK | CCM_CS1CDR_SAI1_CLK_PODF_MASK)) + | CCM_CS1CDR_SAI1_CLK_PRED(n1 - 1) // &0x07 + | CCM_CS1CDR_SAI1_CLK_PODF(n2 - 1); // &0x3f + + IOMUXC_GPR_GPR1 = (IOMUXC_GPR_GPR1 & ~(IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL_MASK)) + | (IOMUXC_GPR_GPR1_SAI1_MCLK_DIR | IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL(0)); //Select MCLK + + + // configure transmitter + int rsync = 0; + int tsync = 1; + + I2S1_TMR = 0; + I2S1_TCR1 = I2S_TCR1_RFW(0); + I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_BCP | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(1); + I2S1_TCR3 = I2S_TCR3_TCE; + I2S1_TCR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(15) | I2S_TCR4_MF | I2S_TCR4_FSD /*| I2S_TCR4_FSE*/ | I2S_TCR4_FSP ; //PT8211 + I2S1_TCR5 = I2S_TCR5_WNW(15) | I2S_TCR5_W0W(15) | I2S_TCR5_FBT(15); + + I2S1_RMR = 0; + I2S1_RCR1 = I2S_RCR1_RFW(0); + I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_RCR2_BCP | I2S_RCR2_MSEL(1)| I2S_RCR2_BCD | I2S_RCR2_DIV(1) ; + I2S1_RCR3 = I2S_RCR3_RCE; + I2S1_RCR4 = I2S_RCR4_FRSZ(1) | I2S_RCR4_SYWD(15) | I2S_RCR4_MF /*| I2S_RCR4_FSE*/ | I2S_RCR4_FSP | I2S_RCR4_FSD; //PT8211 + I2S1_RCR5 = I2S_RCR5_WNW(15) | I2S_RCR5_W0W(15) | I2S_RCR5_FBT(15); + + CORE_PIN21_CONFIG = 3; // RX_BCLK + CORE_PIN20_CONFIG = 3; // RX_SYNC + CORE_PIN7_CONFIG = 3; // TX_DATA0 + I2S1_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE; + I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE ;//<-- not using DMA */; +} //DMAMEM __attribute__((aligned(32))) static uint32_t i2s_tx[1024]; @@ -277,7 +326,6 @@ static uint32_t * i2s_tx_buffer __attribute__((aligned(32))); static uint16_t * i2s_tx_buffer16; static uint16_t * txreg = (uint16_t *)((uint32_t)&I2S1_TDR0 + 2); - FASTRUN void AudioPlaySystem::AUDIO_isr() { *txreg = i2s_tx_buffer16[cnt]; @@ -335,7 +383,14 @@ FLASHMEM void AudioPlaySystem::begin_audio(int samplesize, void (*callback)(shor sampleBufferSize = samplesize; +#ifdef PT8211 + txreg = (uint16_t *)((uint32_t)&I2S1_TDR0); + config_pt8211(); +#else + txreg = (uint16_t *)((uint32_t)&I2S1_TDR0 + 2); config_sai1(); +#endif + attachInterruptVector(IRQ_SAI1, AUDIO_isr); NVIC_ENABLE_IRQ(IRQ_SAI1); NVIC_SET_PRIORITY(IRQ_QTIMER3, 0); // 0 highest priority, 255 = lowest priority @@ -358,4 +413,3 @@ FLASHMEM void AudioPlaySystem::end_audio() } #endif -#endif diff --git a/MCUME_teensy41/teecomputeraudiovideotest/AudioPlaySystem.h b/MCUME_teensy41/teecomputeraudiovideotest/AudioPlaySystem.h index fb22cdc..6d2e23b 100644 --- a/MCUME_teensy41/teecomputeraudiovideotest/AudioPlaySystem.h +++ b/MCUME_teensy41/teecomputeraudiovideotest/AudioPlaySystem.h @@ -19,13 +19,10 @@ public: void buzz(int size, int val); void step(void); static void snd_Mixer(short * stream, int len ); -#ifndef HAS_T4_VGA void begin_audio(int samplesize, void (*callback)(short * stream, int len)); void end_audio(); static void AUDIO_isr(void); - static void SOFTWARE_isr(void); -#endif - + static void SOFTWARE_isr(void); }; diff --git a/MCUME_teensy41/teecomputeraudiovideotest/emuapi.cpp b/MCUME_teensy41/teecomputeraudiovideotest/emuapi.cpp new file mode 100644 index 0000000..e128cca --- /dev/null +++ b/MCUME_teensy41/teecomputeraudiovideotest/emuapi.cpp @@ -0,0 +1,2042 @@ +#define KEYMAP_PRESENT 1 + +extern "C" { + #include "emuapi.h" + #include "iopins.h" +} + +#include + +#ifdef HAS_USB +#include "USBHost_t36.h" // Read this header first for key info +USBHost myusb; +USBHub hub1(myusb); +#ifdef HAS_USBKEY +KeyboardController keyboard1(myusb); +USBHIDParser hid1(myusb); +MouseController mouse1(myusb); +#endif +#ifdef HAS_USBMIDI +MIDIDevice midi1(myusb); +#endif +#ifdef HAS_USBJOY +#define COUNT_JOYSTICKS 4 +JoystickController joysticks[COUNT_JOYSTICKS](myusb); +#endif +#endif + +static bool emu_writeConfig(void); +static bool emu_readConfig(void); +static bool emu_eraseConfig(void); +static bool emu_writeGfxConfig(char * display_type); +static int emu_readGfxConfig(void); + +static bool mouseDetected = false; +static bool keyboardDetected = false; +static uint8_t usbnavpad=0; + +#include +static File file; + +#define MAX_FILES 64 +#define AUTORUN_FILENAME "autorun.txt" +#define GFX_CFG_FILENAME "gfxmode.txt" + +#define MAX_FILENAME_SIZE 34 +#define MAX_MENULINES 9 +#define TEXT_HEIGHT 16 +#define TEXT_WIDTH 8 +#define MENU_FILE_XOFFSET (2*TEXT_WIDTH) +#define MENU_FILE_YOFFSET (2*TEXT_HEIGHT) +#define MENU_FILE_W (MAX_FILENAME_SIZE*TEXT_WIDTH) +#define MENU_FILE_H (MAX_MENULINES*TEXT_HEIGHT) +#define MENU_FILE_BGCOLOR RGBVAL16(0x00,0x00,0x40) +#define MENU_JOYS_YOFFSET (12*TEXT_HEIGHT) +#define MENU_VBAR_XOFFSET (0*TEXT_WIDTH) +#define MENU_VBAR_YOFFSET (MENU_FILE_YOFFSET) + +#define MENU_TFT_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) +#define MENU_TFT_YOFFSET (MENU_VBAR_YOFFSET+32) +#define MENU_VGA_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) +#define MENU_VGA_YOFFSET (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37) + +#include "t4_dsp.h" +T4_DSP tft; + +static int nbFiles=0; +static int curFile=0; +static int topFile=0; +static char selection[MAX_FILENAME_PATH]=""; +static char second_selection[MAX_FILENAME_PATH]=""; +static char files[MAX_FILES][MAX_FILENAME_SIZE]; +static char selected_filename[MAX_FILENAME_SIZE]=""; +static char second_selected_filename[MAX_FILENAME_SIZE]=""; +static bool menuRedraw=true; +static bool autorun=false; +static bool vgahires=false; + + +static const unsigned short * keys; +#ifdef TEECOMPUTER +static unsigned char keymatrix[6]; +static int keymatrix_hitrow=-1; +static uint32_t keypress_t_ms=0; +static uint32_t last_t_ms=0; +static uint32_t hundred_ms_cnt=0; +static bool ledflash_toggle=false; +#endif +static bool key_extmode=false; +static bool key_sh=false; +static bool key_fn=false; + +static boolean joySwapped = false; +static uint16_t bLastState; +#ifdef PIN_JOY2_A1X +static int xRef; +static int yRef; +#endif +static bool menuOn=true; + + +/******************************** + * Generic output and malloc +********************************/ +void emu_printf(const char * text) +{ + Serial.println(text); +} + +void emu_printf(int val) +{ + Serial.println(val); +} + +void emu_printi(int val) +{ + Serial.println(val,HEX); +} + +void emu_printh(int val) +{ + Serial.println(val,HEX); +} + +static int malbufpt = 0; +static char malbuf[EXTRA_HEAP]; + +void * emu_Malloc(unsigned int size) +{ + void * retval = malloc(size); + if (!retval) { + emu_printf("failled to allocate"); + emu_printf(size); + emu_printf("fallback"); + if ( (malbufpt+size) < sizeof(malbuf) ) { + retval = (void *)&malbuf[malbufpt]; + malbufpt += size; + } + else { + emu_printf("failure to allocate"); + } + } + else { + emu_printf("could allocate dynamic "); + emu_printf(size); + } + + return retval; +} + +void * emu_MallocI(unsigned int size) +{ + void * retval = NULL; + + if ( (malbufpt+size) < sizeof(malbuf) ) { + retval = (void *)&malbuf[malbufpt]; + malbufpt += size; + emu_printf("could allocate static "); + emu_printf(size); + } + else { + emu_printf("failure to allocate"); + } + + return retval; +} +void emu_Free(void * pt) +{ + free(pt); +} + +#define SMEMPOOL (0x800000) +EXTMEM static unsigned char slowmem[SMEMPOOL]; +static int slowmempt = 0; + +void * emu_SMalloc(unsigned int size) +{ + void * mem = (void*)&slowmem[slowmempt]; + slowmempt += size; + + if ( slowmempt > SMEMPOOL ) { + mem = NULL; + emu_printf("failure to allocate slow"); + } + else { + emu_printf("could allocate slow static "); + emu_printf(size); + } + return mem; +} + +void emu_SFree(void * pt) +{ +} +/******************************** + * Input and keyboard +********************************/ +#ifdef PIN_JOY2_A1X +int emu_ReadAnalogJoyX(int min, int max) +{ + int val = analogRead(PIN_JOY2_A1X); +#if INVX + val = 4095 - val; +#endif + val = val-xRef; + val = ((val*140)/100); + if ( (val > -512) && (val < 512) ) val = 0; + val = val+2048; + return (val*(max-min))/4096; +} +#endif + +#ifdef PIN_JOY2_A2Y +int emu_ReadAnalogJoyY(int min, int max) +{ + int val = analogRead(PIN_JOY2_A2Y); +#if INVY + val = 4095 - val; +#endif + val = val-yRef; + val = ((val*120)/100); + if ( (val > -512) && (val < 512) ) val = 0; + //val = (val*(max-min))/4096; + val = val+2048; + //return val+(max-min)/2; + return (val*(max-min))/4096; +} +#endif + +static uint16_t readAnalogJoystick(void) +{ + uint16_t joysval = 0; + +#ifdef PIN_JOY2_A1X + int xReading = emu_ReadAnalogJoyX(0,256); + if (xReading > 128) joysval |= MASK_JOY2_LEFT; + else if (xReading < 128) joysval |= MASK_JOY2_RIGHT; + + int yReading = emu_ReadAnalogJoyY(0,256); + if (yReading < 128) joysval |= MASK_JOY2_UP; + else if (yReading > 128) joysval |= MASK_JOY2_DOWN; +#endif + +#ifdef PIN_JOY2_BTN + joysval |= (digitalRead(PIN_JOY2_BTN) == HIGH ? 0 : MASK_JOY2_BTN); +#endif + return (joysval); +} + + +int emu_SwapJoysticks(int statusOnly) { + if (!statusOnly) { + if (joySwapped) { + joySwapped = false; + } + else { + joySwapped = true; + } + } + return(joySwapped?1:0); +} + +int emu_GetPad(void) +{ + return(bLastState/*|((joySwapped?1:0)<<7)*/); +} + +int emu_ReadKeys(void) +{ + uint16_t retval; + uint16_t j1 = readAnalogJoystick(); + uint16_t j2 = 0; + + // Second joystick +#ifdef PIN_JOY1_1 + if ( digitalRead(PIN_JOY1_1) == LOW ) j2 |= MASK_JOY2_UP; +#endif +#ifdef PIN_JOY1_2 + if ( digitalRead(PIN_JOY1_2) == LOW ) j2 |= MASK_JOY2_DOWN; +#endif +#ifdef PIN_JOY1_3 + if ( digitalRead(PIN_JOY1_3) == LOW ) j2 |= MASK_JOY2_RIGHT; +#endif +#ifdef PIN_JOY1_4 + if ( digitalRead(PIN_JOY1_4) == LOW ) j2 |= MASK_JOY2_LEFT; +#endif +#ifdef PIN_JOY1_BTN + if ( digitalRead(PIN_JOY1_BTN) == LOW ) j2 |= MASK_JOY2_BTN; +#endif + if (joySwapped) { + retval = ((j1 << 8) | j2); + } + else { + retval = ((j2 << 8) | j1); + } + + if (usbnavpad & MASK_JOY2_UP) retval |= MASK_JOY2_UP; + if (usbnavpad & MASK_JOY2_DOWN) retval |= MASK_JOY2_DOWN; + if (usbnavpad & MASK_JOY2_LEFT) retval |= MASK_JOY2_LEFT; + if (usbnavpad & MASK_JOY2_RIGHT) retval |= MASK_JOY2_RIGHT; + if (usbnavpad & MASK_JOY2_BTN) retval |= MASK_JOY2_BTN; + if (usbnavpad & MASK_KEY_USER1) retval |= MASK_KEY_USER1; + if (usbnavpad & MASK_KEY_USER2) retval |= MASK_KEY_USER2; + +#ifdef PIN_KEY_USER1 + if ( digitalRead(PIN_KEY_USER1) == LOW ) retval |= MASK_KEY_USER1; +#endif +#ifdef PIN_KEY_USER2 + if ( digitalRead(PIN_KEY_USER2) == LOW ) retval |= MASK_KEY_USER2; +#endif +#ifdef PIN_KEY_USER3 + if ( digitalRead(PIN_KEY_USER3) == LOW ) retval |= MASK_KEY_USER3; +#endif +#ifdef PIN_KEY_USER4 + if ( digitalRead(PIN_KEY_USER4) == LOW ) retval |= MASK_KEY_USER4; +#endif + +#ifdef TEECOMPUTER + keymatrix_hitrow = -1; + unsigned char row; + unsigned short cols[6]={KCOLOUT1,KCOLOUT2,KCOLOUT3,KCOLOUT4,KCOLOUT5,KCOLOUT6}; + for (int i=0;i<6;i++){ + pinMode(cols[i],OUTPUT); + digitalWrite(cols[i], 0); + row=0; + row |= (digitalRead(KROWIN1) ? 0 : 0x01); + row |= (digitalRead(KROWIN2) ? 0 : 0x02); + row |= (digitalRead(KROWIN3) ? 0 : 0x04); + row |= (digitalRead(KROWIN4) ? 0 : 0x08); + row |= (digitalRead(KROWIN5) ? 0 : 0x10); + row |= (digitalRead(KROWIN6) ? 0 : 0x20); + row |= (digitalRead(KROWIN7) ? 0 : 0x40); + digitalWrite(cols[i], 1); + pinMode(cols[i],INPUT_DISABLE); + keymatrix[i]=row; + } + + bool fn_pressed=false; + if ( keymatrix[5] & 0x08 ) {fn_pressed=true; keymatrix[5] &= ~0x08;}; + + bool sh_pressed=false; + if ( keymatrix[5] & 0x10 ) {sh_pressed=true; keymatrix[5] &= ~0x10;}; + + for (int i=0;i<6;i++){ + row = keymatrix[i]; + if (row) keymatrix_hitrow=i; + } + + //6,9,15,8,7,22 +#if INVX + if ( row & 0x40 ) retval |= MASK_JOY2_LEFT; + if ( row & 0x20 ) retval |= MASK_JOY2_RIGHT; +#else + if ( row & 0x20 ) retval |= MASK_JOY2_LEFT; + if ( row & 0x40 ) retval |= MASK_JOY2_RIGHT; +#endif +#if INVY + if ( row & 0x4 ) retval |= MASK_JOY2_DOWN; + if ( row & 0x1 ) retval |= MASK_JOY2_UP; +#else + if ( row & 0x1 ) retval |= MASK_JOY2_DOWN; + if ( row & 0x4 ) retval |= MASK_JOY2_UP; +#endif + if ( row & 0x02 ) retval |= MASK_JOY2_BTN; + + +#ifdef EXTPAD + if ( sh_pressed ) retval |= MASK_KEY_USER3; + if ( fn_pressed ) retval |= MASK_KEY_USER1; + digitalWrite(KLED, 0); +#else + // Handle LED flash + uint32_t time_ms=millis(); + if ((time_ms-last_t_ms) > 100) { + last_t_ms = time_ms; + if (ledflash_toggle == false) { + ledflash_toggle = true; + } + else { + ledflash_toggle = false; + } + } + + if ( sh_pressed ) { + key_sh = true; + } + else { + key_sh = false; + if ( fn_pressed ) { + if (key_fn == false) + { + // Release to Press transition + if (hundred_ms_cnt == 0) { + keypress_t_ms=time_ms; + hundred_ms_cnt += 1; // 1 + } + else { + hundred_ms_cnt += 1; // 2 + if (hundred_ms_cnt >= 2) + { + hundred_ms_cnt = 0; + if ( (time_ms-keypress_t_ms) < 500) + { + if (key_extmode == false) + { + key_extmode = true; + } + else + { + key_extmode = false; + } + } + } + } + } + else { + // Keep press + if (hundred_ms_cnt == 1) { + if ((millis()-keypress_t_ms) > 1000) + { + if (key_extmode == false) + { + key_extmode = true; + } + else + { + key_extmode = false; + } + hundred_ms_cnt = 0; + } + } + } + key_fn = true; + } + else { + key_fn = false; + } + } + + // Handle LED + if (key_extmode == true) { + digitalWrite(KLED, (ledflash_toggle?1:0)); + } + else { + if ( (key_fn == true) || (key_sh == true) ) { + digitalWrite(KLED, 1); + } + else { + digitalWrite(KLED, 0); + } + } + + if ( key_fn ) retval |= MASK_KEY_USER2; + if ( ( key_fn ) && (keymatrix[4] == 0x10 )) retval |= MASK_KEY_USER1; +#endif + + if ( (fn_pressed) && (sh_pressed) ) +#else + if ( ((retval & (MASK_KEY_USER1+MASK_KEY_USER2)) == (MASK_KEY_USER1+MASK_KEY_USER2)) + || (retval & MASK_KEY_USER4 ) ) +#endif + { +// Reset procedure T3.X and T4.0 by Frank Boesing !! +#if defined(__IMXRT1052__) || defined(__IMXRT1062__) + uint32_t tmp = SNVS_LPCR; // save control register + + SNVS_LPSR |= 1; + + // disable alarm + SNVS_LPCR &= ~0x02; + while (SNVS_LPCR & 0x02); + + __disable_irq(); + //get Time: + uint32_t lsb, msb; + do { + msb = SNVS_LPSRTCMR; + lsb = SNVS_LPSRTCLR; + } while ( (SNVS_LPSRTCLR != lsb) | (SNVS_LPSRTCMR != msb) ); + uint32_t secs = (msb << 17) | (lsb >> 15); + + //set alarm + secs += 2; + SNVS_LPTAR = secs; + while (SNVS_LPTAR != secs); + + SNVS_LPCR = tmp | 0x02; // restore control register and set alarm + while (!(SNVS_LPCR & 0x02)); + + SNVS_LPCR |= (1 << 6); // turn off power + while (1) asm("wfi"); +#else + *(volatile uint32_t *)0xE000ED0C = 0x5FA0004; + while (true) { + ; + } +#endif + } + + emu_GetJoystick(); + + return (retval); +} + +unsigned short emu_DebounceLocalKeys(void) +{ + uint16_t bCurState = emu_ReadKeys(); + uint16_t bClick = bCurState & ~bLastState; + bLastState = bCurState; + + return (bClick); +} + +int emu_ReadI2CKeyboard(void) { + int retval=0; +#ifdef TEECOMPUTER + if (key_extmode) { + if (key_fn) { + keys = (const unsigned short *)key_map5; // fn-extra + } + else if (key_sh) { + keys = (const unsigned short *)key_map4; // shift-functionkeys + } + else { + keys = (const unsigned short *)key_map3; // def-digitkeys + } + } + else { + if (key_fn) { + keys = (const unsigned short *)key_map2; // fn-shiftothers + } + else if (key_sh) { + keys = (const unsigned short *)key_map1; // shift-uppercase + } + else { + keys = (const unsigned short *)key_map0; // def-lowercase + } + } + + + if (keymatrix_hitrow >=0 ) { + unsigned short match = ((unsigned short)keymatrix_hitrow<<8) | keymatrix[keymatrix_hitrow]; + for (unsigned int i=0; i= 128) { + midiDataCnt = 0; + midiLastCmd = value; + switch (value & 0xF0) { + case 128: // 0x80 + midiCmdNbParam = 2; + //Serial.print("note off: "); + //Serial.println(value&0xf); + break; + case 144: //0x90 + midiCmdNbParam = 2; + //Serial.print("note on: "); + //Serial.println(value&0xf); + break; + case 160: //0xA0 + midiCmdNbParam = 2; + //Serial.print("aftertouch: "); // rare + //Serial.println(value&0xf); + break; + case 176: //0xB0 + midiCmdNbParam = 2; + //Serial.print("continuous controller: "); + //Serial.println(value&0xf); + break; + case 192: //0xC0 + midiCmdNbParam = 1; + //Serial.print("patch change: "); //some + //Serial.println(value&0xf); + break; + case 208: //0xD0 + midiCmdNbParam = 1; + Serial.print("channel pressure: "); + Serial.println(value&0xf); + break; + case 224: //0xE0 + midiCmdNbParam = 2; + //Serial.print("pitch bend: "); + //Serial.println(value&0xf); + break; + case 240: //0xF0 + // non-musical commands + switch (value) { + case 0xF0: + //Serial.println("NI: System Exclusive"); + break; + case 0xF1: + //Serial.println("NI: System Common - MIDI Time Code Quarter Frame"); + break; + case 0xF2: + midiCmdNbParam = 2; + break; + case 0xF3: + //Serial.println("NI: System Common - Song Select"); + break; + case 0xF6: + //Serial.println("NI: System Common - Tune Request"); + break; + case 0xF8: + //Serial.println("System Real Time - Timing Clock"); + midi1.sendRealTime(value, 0); + break; + case 0xFA: + //Serial.println("System Real Time - Start"); + midi1.sendRealTime(value, 0); + break; + case 0xFB: + //Serial.println("System Real Time - Continue"); + midi1.sendRealTime(value, 0); + break; + case 0xFC: + //Serial.println("System Real Time - Stop"); + midi1.sendRealTime(value, 0); + break; + case 0xFE: + //Serial.println("System Real Time - Active Sensing"); + midi1.sendRealTime(value, 0); + break; + case 0xFF: + //Serial.println("System Real Time - System Reset"); + midi1.sendRealTime(value, 0); + break; + } + //SystemExclusive = 0xF0, // System Exclusive + //TimeCodeQuarterFrame = 0xF1, // System Common - MIDI Time Code Quarter Frame + //SongPosition = 0xF2, // System Common - Song Position Pointer + //SongSelect = 0xF3, // System Common - Song Select + //TuneRequest = 0xF6, // System Common - Tune Request + //Clock = 0xF8, // System Real Time - Timing Clock + //Start = 0xFA, // System Real Time - Start + //Continue = 0xFB, // System Real Time - Continue + //Stop = 0xFC, // System Real Time - Stop + //ActiveSensing = 0xFE, // System Real Time - Active Sensing + //SystemReset = 0xFF, // System Real Time - System Reset + break; + default: + Serial.print("??: "); + Serial.println(value&0xf); + break; + } + } + else { + if (midiDataCnt<16) midiBuffer[midiDataCnt++] = value ; + if ( (midiLastCmd & 0xF0) == 240) { + if (midiLastCmd == 0xF2) { + if (midiDataCnt == midiCmdNbParam) { + //Serial.println("System Common - Song Position Pointer"); + midi1.sendSongPosition(((int)midiBuffer[1]<<7)+(int)midiBuffer[0], 0); + } + } + else { + Serial.println(value); + } + } + else if (midiDataCnt == midiCmdNbParam) { + unsigned char chan = (midiLastCmd&0xf)+1; + //Serial.print("ch "); + //Serial.println(chan); + switch (midiLastCmd & 0xF0) { + case 128: //0x80 + //Serial.print("note off: "); + midi1.sendNoteOff(midiBuffer[0], midiBuffer[1], chan); + break; + case 144: //0x90 + //Serial.print("note on: "); + midi1.sendNoteOn(midiBuffer[0], midiBuffer[1], chan); + break; + case 160: //0xA0 + //Serial.print("aftertouch: "); + midi1.sendPolyPressure(midiBuffer[0], midiBuffer[1], chan); + break; + case 176: //0xB0 + //Serial.print("continuous controller: "); + midi1.sendControlChange(midiBuffer[0], midiBuffer[1], chan); + break; + case 192: //0xC0 + //Serial.print("patch change: "); + midi1.sendProgramChange(midiBuffer[0], chan); + break; + case 208: //0xD0 + //Serial.print("channel pressure: "); + midi1.sendAfterTouch(midiBuffer[0], chan); + break; + case 224: //0xE0 + //Serial.print("pitch bend: "); + midi1.sendPitchBend((((int)midiBuffer[1]<<7)+(int)midiBuffer[0])-8192, chan); + break; + default: + Serial.print("??: "); + break; + } + } + } +#endif +} + +/******************************** + * Menu file loader UI +********************************/ +#ifdef FILEBROWSER +static int readNbFiles(void) { + int totalFiles = 0; + + File entry; + file = SD.open(selection); + while ( (true) && (totalFiles=0) { + menuRedraw=true; + curFile -= 9; + } else if (curFile!=0) { + menuRedraw=true; + curFile--; + } + } + else if ( (bClick & MASK_JOY2_DOWN) || (bClick & MASK_JOY1_DOWN) ) { + if ((curFile<(nbFiles-1)) && (nbFiles)) { + curFile++; + menuRedraw=true; + } + } + else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { + if ((curFile<(nbFiles-9)) && (nbFiles)) { + curFile += 9; + menuRedraw=true; + } + else if ((curFile<(nbFiles-1)) && (nbFiles)) { + curFile++; + menuRedraw=true; + } + } + + if (menuRedraw && nbFiles) { + int fileIndex = 0; + tft.drawRectNoDma(MENU_FILE_XOFFSET,MENU_FILE_YOFFSET, MENU_FILE_W, MENU_FILE_H, MENU_FILE_BGCOLOR); +// if (curFile <= (MAX_MENULINES/2-1)) topFile=0; +// else topFile=curFile-(MAX_MENULINES/2); + if (curFile <= (MAX_MENULINES-1)) topFile=0; + else topFile=curFile-(MAX_MENULINES/2); + + //Serial.print("curfile: "); + //Serial.println(curFile); + //Serial.print("topFile: "); + //Serial.println(topFile); + + int i=0; + while (i=nbFiles) { + // no more files + break; + } + char * filename = &files[fileIndex][0]; + if (fileIndex >= topFile) { + if ((i+topFile) < nbFiles ) { + if ((i+topFile)==curFile) { + tft.drawTextNoDma(MENU_FILE_XOFFSET,i*TEXT_HEIGHT+MENU_FILE_YOFFSET, filename, RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); + strcpy(selected_filename,filename); + } + else { + tft.drawTextNoDma(MENU_FILE_XOFFSET,i*TEXT_HEIGHT+MENU_FILE_YOFFSET, filename, RGBVAL16(0xff,0xff,0xff), MENU_FILE_BGCOLOR, true); + } + } + i++; + } + fileIndex++; + } + + +// tft.drawTextNoDma(48,MENU_JOYS_YOFFSET+8, (emu_SwapJoysticks(1)?(char*)"SWAP=1":(char*)"SWAP=0"), RGBVAL16(0x00,0xff,0xff), RGBVAL16(0x00,0x00,0xff), false); + tft.drawTextNoDma(48,MENU_JOYS_YOFFSET+8, "FLOPPY2:", RGBVAL16(0x00,0xff,0xff), RGBVAL16(0x00,0x00,0xff), false); + tft.drawRectNoDma(120,MENU_JOYS_YOFFSET+8, MENU_FILE_W, 8, RGBVAL16(0x00,0x00,0x00)); + tft.drawTextNoDma(120,MENU_JOYS_YOFFSET+8, second_selected_filename, RGBVAL16(0xff,0xff,0xff), RGBVAL16(0x00,0x00,0x00), false); + menuRedraw=false; + } + + return (action); +} + +int menuActive(void) +{ + return (menuOn?1:0); +} + +void toggleMenu(int on) { + if (on) { + menuOn=true; + backgroundMenu(); + } else { + menuOn = false; + } +} + +char * menuSelection(void) +{ + return (selection); +} + +char * menuSecondSelection(void) +{ + return (second_selection); +} +#endif + +/******************************** + * OSKB handling +********************************/ +static bool oskbOn = false; +static int cxpos = 0; +static int cypos = 0; +static uint16_t oskbBLastState = 0; +#define OSKBHEIGHT 4 +#define OSKBXOFF 16 +#define OSKBYOFF 0 + +static void lineOSKB(int xoff, bool bottom, char * str, int row) +{ + char c[4] = {' ',0,' ',0}; + const char * cpt = str; + int i=0; + int fb_width,fb_height,fbstride; + + fbstride = tft.get_frame_buffer_size(&fb_width, &fb_height); + int ypos = (bottom?(fb_height-2*8):0); + int line = row + (bottom?2:0); + while ((c[1] = *cpt++)) + { + uint16_t bg; + if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0); + else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff); + if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff); + tft.drawText(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); + i++; + } +} + +static int linelenOSKB() { + if (cypos == 0) return strlen(keylables_map0_0); + else if (cypos == 1) return strlen(keylables_map0_1); + else if (cypos == 2) return strlen(keylables_map0_2); + else return strlen(keylables_map0_3); +} + +static void drawOSKB() { + if (key_extmode) { + if (key_fn) { + lineOSKB(16,false, keylables_map5_0, 0); + lineOSKB(8, false, keylables_map5_1, 1); + lineOSKB(0, true, keylables_map5_2, 0); + lineOSKB(96,true, keylables_map5_3, 1); + } + else if (key_sh) { + lineOSKB(16,false, keylables_map4_0, 0); + lineOSKB(8, false, keylables_map4_1, 1); + lineOSKB(0, true, keylables_map4_2, 0); + lineOSKB(96,true, keylables_map4_3, 1); + } + else { + lineOSKB(16,false, keylables_map3_0, 0); + lineOSKB(8, false, keylables_map3_1, 1); + lineOSKB(0, true, keylables_map3_2, 0); + lineOSKB(96,true, keylables_map3_3, 1); + } + } + else { + if (key_fn) { + lineOSKB(16,false, keylables_map2_0, 0); + lineOSKB(8, false, keylables_map2_1, 1); + lineOSKB(0, true, keylables_map2_2, 0); + lineOSKB(96,true, keylables_map2_3, 1); + } + else if (key_sh) { + lineOSKB(16,false, keylables_map1_0, 0); + lineOSKB(8, false, keylables_map1_1, 1); + lineOSKB(0, true, keylables_map1_2, 0); + lineOSKB(96,true, keylables_map1_3, 1); + } + else { + lineOSKB(16,false, keylables_map0_0, 0); + lineOSKB(8, false, keylables_map0_1, 1); + lineOSKB(0, true, keylables_map0_2, 0); + lineOSKB(96,true, keylables_map0_3, 1); + } + } +} + +int handleOSKB(void) { + int retval = 0; + if (oskbOn) { + uint16_t bClick = bLastState & ~oskbBLastState; + oskbBLastState = bLastState; + bool updated = true; + if (bClick & MASK_KEY_USER1) + { + } + else if (bClick & MASK_JOY2_RIGHT) + { + cxpos++; + if (cxpos >= linelenOSKB()) cxpos = 0; + } + else if (bClick & MASK_JOY2_LEFT) + { + cxpos--; + if (cxpos < 0) cxpos = linelenOSKB()-1; + } + else if (bClick & MASK_JOY2_DOWN) + { + cypos++; + if (cypos >= OSKBHEIGHT) cypos = 0; + if (cxpos >= linelenOSKB()) cxpos = linelenOSKB()-1; + } + else if (bClick & MASK_JOY2_UP) + { + cypos--; + if (cypos < 0) cypos = OSKBHEIGHT-1; + if (cxpos >= linelenOSKB()) cxpos = linelenOSKB()-1; + } + else if (oskbBLastState & MASK_JOY2_BTN) + { + //if (retval) { toggleOSKB(false); updated=false; }; + } + else { + updated=false; + } + /*if (updated)*/ drawOSKB(); + } + return retval; +} + +void toggleOSKB(int forceon) { + if (forceon) { + oskbOn = true; + drawOSKB(); + } + else { + if (oskbOn) { + oskbOn = false; + } + else { + oskbOn = true; + drawOSKB(); + } + } +} + + + +/******************************** + * File IO +********************************/ +static File file_handlers[NB_FILE_HANDLER]; + +static void FileHandlersInit(void) { + for (int i=0; i= 0) { + if ((file_handlers[handler] = SD.open(filepath, O_READ))) { + // emu_printi(handler+1); + retval = handler+1; + } + else { + file_handlers[handler] = file; + emu_printf("FileOpen failed"); + } + } + return (retval); +#endif +} + +int emu_FileRead(void * buf, int size, int handler) +{ +// emu_printf("FileRead"); +// emu_printi(handler); +#ifdef HCFH + return (file.read(buf, size)); +#else + return (getFileHandler(handler).read(buf, size)); +#endif +} + +int emu_FileWrite(void * buf, int size, int handler) +{ +// emu_printf("emu_FileWrite"); +// emu_printi(handler); +#ifdef HCFH + return (file.write(buf, size)); +#else + return (getFileHandler(handler).write(buf, size)); +#endif +} + +int emu_FileGetc(int handler) { +// emu_printf("FileGetc"); +// emu_printi(handler); +#ifdef HCFH + unsigned char c; + int retval = file.read(&c, 1); + if (retval != 1) { + emu_printf("emu_FileGetc failed"); + } + return (int)c; +#else + unsigned char c; + int retval = getFileHandler(handler).read(&c, 1); + if (retval != 1) { + emu_printf("emu_FileGetc failed"); + } + return (int)c; +#endif +} + +int emu_FileSeek(int handler, int seek, int origin) +{ +// emu_printf("FileSeek"); +// emu_printi(handler); +// emu_printi(seek); +#ifdef HCFH + file.seek(seek); + return (seek); +#else + getFileHandler(handler).seek(seek); + return (seek); +#endif +} + +int emu_FileTell(int handler) { +// emu_printf("FileTell"); +// emu_printi(handler); +#ifdef HCFH + return (50); +#else + File file = getFileHandler(handler); + return (emu_FileSize((char*)file.name())); +#endif +} + + +void emu_FileClose(int handler) +{ +// emu_printf("FileClose"); +// emu_printi(handler); +#ifdef HCFH + file.close(); +#else + getFileHandler(handler).close(); + file_handlers[handler-1] = file; +#endif +} + + +static File lofile; + +unsigned int emu_FileSize(const char * filepath) +{ + unsigned int filesize=0; + emu_printf(filepath); + if ((lofile = SD.open(filepath, O_READ))) + { + emu_printf("filesize is..."); + filesize = lofile.size(); + emu_printf(filesize); + lofile.close(); + } + else { + emu_printf("filesize failed"); + } + return(filesize); +} + +unsigned int emu_LoadFile(const char * filepath, void * buf, int size) +{ + unsigned int filesize = 0; + emu_printf("LoadFile..."); + emu_printf(filepath); + if ((lofile = SD.open(filepath, O_READ))) + { + filesize = lofile.size(); + emu_printf(filesize); + if ((unsigned int)size >= filesize) + { + if (lofile.read(buf, filesize) != filesize) + { + emu_printf("File read failed"); + } + } + lofile.close(); + } + return(filesize); +} + +unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek) +{ + unsigned int filesize = 0; + emu_printf("LoadFileSeek..."); + emu_printf(filepath); + if ((lofile = SD.open(filepath, O_READ))) + { + lofile.seek(seek); + emu_printf(size); + if (lofile.read(buf, size) != (unsigned int)size) { + emu_printf("File read failed"); + } + lofile.close(); + } + return(filesize); +} + +static bool emu_writeConfig(void) +{ + bool retval = false; + if ((lofile = SD.open(ROMSDIR "/" AUTORUN_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(selection, strlen(selection)) != strlen(selection)) { + emu_printf("Config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + return retval; +} + +static bool emu_readConfig(void) +{ + bool retval = false; + + if ((lofile = SD.open(ROMSDIR "/" AUTORUN_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + unsigned int sizeread = lofile.read(selection, filesize); + if (sizeread != filesize) { + emu_printf("Config read failed"); + } + else { + if (sizeread == filesize) + { + selection[filesize]=0; + retval = true; + } + } + lofile.close(); + } + return retval; +} + +static bool emu_eraseConfig(void) +{ + SD.remove (ROMSDIR "/" AUTORUN_FILENAME); +} + +static bool emu_writeGfxConfig(char * display_type) +{ + bool retval = false; + SD.remove ("/" GFX_CFG_FILENAME); + if (strcmp(display_type, "VGA")) { + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(display_type, strlen(display_type)) != strlen(display_type)) { + emu_printf("GFX config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + } + return retval; +} + +#define CFG_VGA 0 +#define CFG_ILI 1 +#define CFG_ST 2 + +static int emu_readGfxConfig(void) +{ + int retval = CFG_VGA; // No file = VGA + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + if (filesize == 2) // "ST" + { + retval = CFG_ST; + } + else if (filesize == 3) // "ILI" + { + retval = CFG_ILI; + } + lofile.close(); + } + return retval; +} + +/******************************** + * File IO compatibility +********************************/ +#ifdef HAS_EXTFF + +#include "ff.h" + +typedef struct { + File f; + int offset; + int size; + int used; +} FileDesc; + +typedef int * FIL; + + + +#define NO_MMAP_HANDLES 32 + +static FileDesc fds[NO_MMAP_HANDLES]; +static int nextHandle=0; + +static void freeHandle(int h) { + fds[h].used = 0; +} + + +static int getFreeHandle() { + int n=NO_MMAP_HANDLES; + while (fds[nextHandle].used!=0 && n!=0) { + nextHandle++; + if (nextHandle==NO_MMAP_HANDLES) nextHandle=0; + n-1; + } + if (n==0) { + emu_printf("getFreeHandle error"); + return; + } + + int r=nextHandle; + fds[r].used = 1; + nextHandle++; + if (nextHandle==NO_MMAP_HANDLES) nextHandle=0; + + return r; +} + +FRESULT f_open (FIL* fp, const char * path, unsigned char mode) +{ + emu_printf("fopen"); + emu_printf((char*)path); + int i=getFreeHandle(); + emu_printf(i); + fds[i].f = SD.open(path, O_READ); + *fp = i; + if (fds[i].f) { + fds[i].size = fds[i].f.size(); + emu_printi(fds[i].size); + return(FR_OK); + } + emu_printf("error"); + freeHandle(fds[i].f); + return(FR_NO_FILE); +} + +FRESULT f_close (FIL* fp) +{ + int i = *fp; + emu_printf("fclose"); + emu_printi(i); + fds[i].f.close(); + freeHandle(i); + return(FR_OK); +} + +FRESULT f_read (FIL* fp, void* buff, unsigned int btr, unsigned int * br) +{ + int i = *fp; + + if (btr < 64738) { + int nr = fds[i].f.read(buff, btr); + //emu_printf("fread"); + //emu_printi(btr); + //emu_printi(nr); + *br = nr; + if (nr <= 0) + return(FR_DISK_ERR); + else + return(FR_OK); + } + + unsigned char buffer[256]; + + int remaining = btr; + int byteread = 0; + int retval=0; + + while (remaining>0) { + if (remaining < 256) + retval = fds[i].f.read(buffer, remaining); + else + retval = fds[i].f.read(buffer, 256); + if (retval>0) { + memcpy(buff,buffer,retval); + buff += retval; + byteread += retval; + remaining -= retval; + } + else { + break; + } + } + *br = byteread; + //emu_printi(byteread); + if (byteread <= 0) + return(FR_DISK_ERR); + else + return(FR_OK); +} + +FRESULT f_readn (FIL* fp, void* buff, unsigned int btr, unsigned int * br) +{ + return(f_read (fp, buff, btr, br)); +} + +FRESULT f_write (FIL* fp, const void* buff, unsigned int btw, unsigned int * bw) +{ + return(FR_OK); +} +FRESULT f_writen (FIL* fp, const void* buff, unsigned int btw, unsigned int * bw) +{ + return(FR_OK); +} +FRESULT f_lseek (FIL* fp, unsigned long ofs) +{ + int i = *fp; + //emu_printf("fseek"); + //emu_printi(ofs); + fds[i].f.seek(ofs); + return(FR_OK); +} + + +FRESULT f_unlink (const char * path) +{ + return(FR_OK); +} +FRESULT f_rename (const char * path_old, const char * path_new) +{ + return(FR_OK); +} +FRESULT f_stat (const char * path, FILINFO* fno) +{ + return(FR_OK); +} + +unsigned long f_tell (FIL * fp) +{ + int i = *fp; + emu_printf("ftell"); + return(fds[i].size); + //return(fds[i].f.ftell()); +} + +unsigned long f_size (FIL * fp) +{ + int i = *fp; + emu_printf("fsize"); + emu_printi(fds[i].size); + return(fds[i].size); +} + +FRESULT f_mkdir (const char* path) +{ + return(FR_OK); +} +#endif + + +/******************************** + * GFX wrapper +********************************/ +static unsigned short palette16[PALETTE_SIZE]; +static IntervalTimer myTimer; +volatile boolean vbl=true; +volatile boolean vgatimervsync=false; +static void (*vblCallback)(void) = nullptr; +static int skip=0; + +static void vblCount() { + if (vbl) { + vbl = false; + } else { + vbl = true; + } +} + +void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) +{ + if (index= MODE_VGA_320x240 ) { + if (vgatimervsync) { + while (vbl==vb) {}; + } + else { + tft.waitSync(); + } + } + else { + while (vbl==vb) {}; + } + if (vblCallback != nullptr) { + vblCallback(); + } +} + +void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride) +{ + if (skip == 0) { + tft.writeScreenPal(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); + } +} +void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLinePal(width,height,line, VBuf, palette16); + } +} + +void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine(width,height,line, VBuf); + } +} + +void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine8(width,height,line, VBuf, palette16); + } +} + +int emu_IsVga(void) +{ + return (tft.getMode() >= MODE_VGA_320x240?1:0); +} + +int emu_IsVgaHires(void) +{ + return (tft.getMode() >= MODE_VGA_640x240?1:0); +} + +int emu_FrameSkip(void) +{ + return skip; +} + + +/******************************** + * AUDIO wrapper +********************************/ +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +AudioPlaySystem mymixer; + +void emu_sndInit() { + Serial.println("sound init"); + mymixer.begin_audio(256, mymixer.snd_Mixer); + mymixer.start(); +} + +void emu_sndPlaySound(int chan, int volume, int freq) +{ + if (chan < 6) { + mymixer.sound(chan, freq, volume); + } + /* + Serial.print(chan); + Serial.print(":" ); + Serial.print(volume); + Serial.print(":" ); + Serial.println(freq); + */ +} + +void emu_sndPlayBuzz(int size, int val) { + mymixer.buzz(size,val); + //Serial.print((val==1)?1:0); + //Serial.print(":"); + //Serial.println(size); +} +#endif + +/******************************** + * Initialization +********************************/ +void emu_init(int hires) +{ + Serial.begin(115200); + vgahires = hires; + +#ifdef HAS_USB + myusb.begin(); +#ifdef HAS_USBKEY + keyboard1.attachPress(OnPress); + keyboard1.attachRelease(OnRelease); +#endif +#endif + +#ifdef FILEBROWSER + if (!SD.begin(SD_CS)) + { + Serial.println("No SD card detected"); + } + strcpy(selection,ROMSDIR); + FileHandlersInit(); + nbFiles = readNbFiles(); + Serial.println(nbFiles); +#endif + + emu_InitJoysticks(); +#ifdef SWAP_JOYSTICK + joySwapped = true; +#else + joySwapped = false; +#endif + + int keypressed = emu_ReadKeys(); +#ifdef HAS_T4_VGA + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } +#else + int gfx_mode = CFG_VGA; // default +#ifdef FILEBROWSER + gfx_mode = emu_readGfxConfig(); +#endif + // Force VGA if UP pressed + if (keypressed & MASK_JOY2_UP) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("VGA"); +#endif + gfx_mode = CFG_VGA; + } + else { + if (keypressed & MASK_JOY2_LEFT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ST"); +#endif + gfx_mode = CFG_ST; + } + else if (keypressed & MASK_JOY2_RIGHT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ILI"); +#endif + gfx_mode = CFG_ILI; + } + } + if (gfx_mode == CFG_VGA) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + else + { + tft.begin(gfx_mode == CFG_ILI?MODE_TFTILI_320x240:MODE_TFTST_320x240); + } +#endif + + if (keypressed & MASK_JOY2_DOWN) { + tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) ); + tft.drawTextNoDma(64,48, (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); +#ifdef FILEBROWSER + emu_eraseConfig(); + delay(1000); +#endif + } + else { +#ifdef FILEBROWSER + if (emu_readConfig()) { + autorun = true; + } +#endif + } + +#ifdef FILEBROWSER + toggleMenu(true); +#endif +} + + +void emu_start(int vblms, void * callback, int forcetimervsync) +{ + vgatimervsync = forcetimervsync?true:false; + tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); + tft.startRefresh(); + if (callback != nullptr) { + vblCallback = callback; + } + + myTimer.begin(vblCount, vblms); +#ifdef HAS_SND + emu_sndInit(); +#endif + usbnavpad = 0; +} diff --git a/MCUME_teensy41/teecomputeraudiovideotest/emuapi.h b/MCUME_teensy41/teecomputeraudiovideotest/emuapi.h new file mode 100644 index 0000000..5dd6130 --- /dev/null +++ b/MCUME_teensy41/teecomputeraudiovideotest/emuapi.h @@ -0,0 +1,105 @@ +#ifndef EMUAPI_H +#define EMUAPI_H + +#include "platform_config.h" +#include "emucfg.h" + +#define ACTION_NONE 0 +#define ACTION_RUN1 1 +#define ACTION_RUN2 2 + +#define FORCE_VGATIMERVSYNC 1 +#define SUPPORT_HIRES 1 + +#define MASK_JOY2_RIGHT 0x0001 +#define MASK_JOY2_LEFT 0x0002 +#define MASK_JOY2_UP 0x0004 +#define MASK_JOY2_DOWN 0x0008 +#define MASK_JOY2_BTN 0x0010 +#define MASK_KEY_USER1 0x0020 +#define MASK_KEY_USER2 0x0040 +#define MASK_KEY_USER3 0x0080 +#define MASK_JOY1_RIGHT 0x0100 +#define MASK_JOY1_LEFT 0x0200 +#define MASK_JOY1_UP 0x0400 +#define MASK_JOY1_DOWN 0x0800 +#define MASK_JOY1_BTN 0x1000 +#define MASK_KEY_USER4 0x2000 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) + +#ifdef __cplusplus +extern "C" { +extern void emu_init(int hires=0); +extern void emu_start(int vblms, void * callback, int forcetimervsync=0); +#endif +extern void emu_printf(const char * text); +extern void emu_printi(int val); +extern void emu_printh(int val); +extern void * emu_Malloc(unsigned int size); +extern void * emu_MallocI(unsigned int size); +extern void emu_Free(void * pt); +extern void * emu_SMalloc(unsigned int size); +extern void emu_SFree(void * pt); + +extern int emu_FileOpen(const char * filepath, const char * mode); +extern int emu_FileRead(void * buf, int size, int handler); +extern int emu_FileWrite(void * buf, int size, int handler); +extern int emu_FileGetc(int handler); +extern int emu_FileSeek(int handler, int seek, int origin); +extern int emu_FileTell(int handler); +extern void emu_FileClose(int handler); + +extern unsigned int emu_FileSize(const char * filepath); +extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size); +extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek); + +extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index); +extern void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line); +extern void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride); +extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawVsync(void); +extern int emu_FrameSkip(void); +extern int emu_IsVga(void); +extern int emu_IsVgaHires(void); + +extern int menuActive(void); +extern char * menuSelection(void); +extern char * menuSecondSelection(void); +extern void toggleMenu(int on); +extern int handleMenu(unsigned short bClick); + +extern int handleOSKB(void); +extern void toggleOSKB(int forceon); + +extern void emu_InitJoysticks(void); +extern int emu_SwapJoysticks(int statusOnly); +extern unsigned short emu_DebounceLocalKeys(void); +extern int emu_ReadKeys(void); +extern int emu_GetPad(void); +extern int emu_GetMouse(int *x, int *y, int *buts); +extern int emu_MouseDetected(void); +extern int emu_GetJoystick(void); +extern int emu_KeyboardDetected(void); +extern int emu_ReadAnalogJoyX(int min, int max); +extern int emu_ReadAnalogJoyY(int min, int max); +extern int emu_ReadI2CKeyboard(void); +extern unsigned char emu_ReadI2CKeyboard2(int row); +extern void emu_KeyboardOnUp(int keymodifer, int key); +extern void emu_KeyboardOnDown(int keymodifer, int key); +extern void emu_MidiOnDataReceived(unsigned char data); + +extern void emu_sndPlaySound(int chan, int volume, int freq); +extern void emu_sndPlayBuzz(int size, int val); +extern void emu_sndInit(); +extern void emu_resetus(void); +extern int emu_us(void); + +extern int emu_setKeymap(int index); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/MCUME_teensy41/teecomputeraudiovideotest/emucfg.h b/MCUME_teensy41/teecomputeraudiovideotest/emucfg.h new file mode 100644 index 0000000..ac1c8b9 --- /dev/null +++ b/MCUME_teensy41/teecomputeraudiovideotest/emucfg.h @@ -0,0 +1,108 @@ +#ifndef EMUCFG_H +#define EMUCFG_H + +// Title: < > +#define TITLE " XXXX Emulator " +#define ROMSDIR "snes" + +#define MAX_FILENAME_PATH 64 +#define NB_FILE_HANDLER 4 +#define PALETTE_SIZE 256 +#define VID_FRAME_SKIP 0x0 +#define TFT_VBUFFER_YCROP 0 +#define SINGLELINE_RENDERING 1 +//#define CUSTOM_SND 1 +//#define TIMER_REND 1 +//#define EXTPAD 1 +#define EXTRA_HEAP 0x10 +//#define FILEBROWSER 1 + + +#ifdef KEYMAP_PRESENT + +#define keylables_map0_0 (char *)"QWERTYUIOP\x1a" +#define keylables_map0_1 (char *)" ASDFGHJKL\x19" +#define keylables_map0_2 (char *)" ZXCVBNM,.;/" +#define keylables_map0_3 (char *)" +\x10-" +const unsigned short key_map0[] = { + 'q','w','E','R','T','Y','U','I','O','P',157, //default C64 uppercase always + 0,'A','S','D','F','G','H','J','K','L',10, + 0,'Z','X','C','V','B','N','M',',','.',';','/', + 0,0,0,0, + 0,'+',' ','-' + }; + +#define keylables_map1_0 (char *)"1234567890 " +#define keylables_map1_1 (char *)" " +#define keylables_map1_2 (char *)" " +#define keylables_map1_3 (char *)" " + +const unsigned short key_map1[] = { + '1','2','3','4','5','6','7','8','9','0',0, // digit keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map2_0 (char *)"!\"#$%^&*()@" +#define keylables_map2_1 (char *)" " +#define keylables_map2_2 (char *)" <>:?" +#define keylables_map2_3 (char *)" =\x10_" +const unsigned short key_map2[] = { + '!','"','#','$','%','^','&','*','(',')','@', // shiftothers + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 153,151,150,152, //U L R D + 0,'=',' ','_' + }; + +#define keylables_map3_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " +#define keylables_map3_1 (char *)" " +#define keylables_map3_2 (char *)" " +#define keylables_map3_3 (char *)" " + +const unsigned short key_map3[] = { + 129,130,131,132,133,134,135,136,0,0,0, // function keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map4_0 (char *)"QWERTYUIOP@" +#define keylables_map4_1 (char *)" ASDFGHJKL\x19" +#define keylables_map4_2 (char *)" ZXCVBNM<>:?" +#define keylables_map4_3 (char *)" =\x10_" +const unsigned short key_map4[] = { + 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase + 0,'A','S','D','F','G','H','J','K','L',10, + 0,'Z','X','C','V','B','N','M','<','>',':','?', + 0,0,0,0, + 0,'=',' ','_' + }; + +#define keylables_map5_0 (char *)" " +#define keylables_map5_1 (char *)" " +#define keylables_map5_2 (char *)" " +#define keylables_map5_3 (char *)" " + +const unsigned short key_map5[] = { + 0,0,0,0,0,0,0,0,0,0,0, // extra keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 153,151,150,152, //U L R D + 0,0,' ',0 + }; + +const unsigned short matkeys[] = { + 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 + 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 + 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 + 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN + 0x510,0x010,0x110,0x310, // row 4 + }; + +#endif + +#endif diff --git a/MCUME_teensy41/teecomputeraudiovideotest/platform_config.h b/MCUME_teensy41/teecomputeraudiovideotest/platform_config.h index 7deff7c..6c68adf 100644 --- a/MCUME_teensy41/teecomputeraudiovideotest/platform_config.h +++ b/MCUME_teensy41/teecomputeraudiovideotest/platform_config.h @@ -1,8 +1,34 @@ #ifndef _PLATFORM_CONFIG_H_ #define _PLATFORM_CONFIG_H_ -#define ST7789 1 -#define TFTSPI1 1 +// Will work on TEECOMPUTER as is +// NO TEECOMPUTER specific switch + +#define HAS_T4_VGA 1 +//#define INVX 1 +#define INVY 1 #define HAS_SND 1 +#define HAS_USB 1 +//#define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 +//#define HAS_USBJOY 1 // not working yet +//#define PT8211 1 + + +//#define FLIP_SCREEN 1 +//#define ILI9341 1 +//#define ST7789 1 +//#define SWAP_JOYSTICK 1 +//#define LOHRES 1 +//#define ROTATE_SCREEN 1 +//#define EXTERNAL_SD 1 + + +//#define USE_SDFAT 1 +//#define SD_FAT_TYPE 1 +//#define USE_SDFS 1 +//#define SDFSDEV "1:" + #endif diff --git a/MCUME_teensy41/teecomputeraudiovideotest/t4_dsp.cpp b/MCUME_teensy41/teecomputeraudiovideotest/t4_dsp.cpp new file mode 100644 index 0000000..43301fa --- /dev/null +++ b/MCUME_teensy41/teecomputeraudiovideotest/t4_dsp.cpp @@ -0,0 +1,1774 @@ +/* + TFT/VGA driver + DMA TFT driver based on C64 ILI9341 dma driver from Frank Bösing, 2017 +*/ + +#include "T4_DSP.h" + +#include +#include + +#include "font8x8.h" + +// TFT constants and variables +#define TFT_LINEARINT 1 +#define LINEARINT_HACK 1 +#define DMA_LINES_PER_BLOCK 64 +#define DMA_NUM_SETTINGS 4 + +#define TFT_SWRESET 0x01 +#define TFT_SLPOUT 0x11 +#define TFT_INVON 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_MADCTL 0x36 +#define TFT_PIXFMT 0x3A +#define TFT_MADCTL_MY 0x80 +#define TFT_MADCTL_MX 0x40 +#define TFT_MADCTL_MV 0x20 +#define TFT_MADCTL_ML 0x10 +#define TFT_MADCTL_RGB 0x00 +#define TFT_MADCTL_BGR 0x08 +#define TFT_MADCTL_MH 0x04 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) +//#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) +//#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) +//#define R16(rgb) ((rgb>>8)&0xf8) +//#define G16(rgb) ((rgb>>3)&0xfc) +//#define B16(rgb) ((rgb<<3)&0xf8) + +// LPSPI4 = SPI0 in Teensy 4.0 +// LPSPI3 = SPI1 in Teensy 4.0 +// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) + +#ifdef TFTSPI1 +#define SPI SPI1 +#define LPSPIP_TDR LPSPI3_TDR +#define LPSPIP_CR LPSPI3_CR +#define LPSPIP_CFGR1 LPSPI3_CFGR1 +#define LPSPIP_TCR LPSPI3_TCR +#define LPSPIP_DER LPSPI3_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX +#else +#define LPSPIP_TDR LPSPI4_TDR +#define LPSPIP_CR LPSPI4_CR +#define LPSPIP_CFGR1 LPSPI4_CFGR1 +#define LPSPIP_TCR LPSPI4_TCR +#define LPSPIP_DER LPSPI4_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX +#endif + +#define SPICLOCK 60000000 +#define SPI_MODE SPI_MODE0 + +// VGA constants and macros +typedef uint8_t vga_pixel; +#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) + +static DMASetting dmasettings[DMA_NUM_SETTINGS]; +static DMAChannel dmatx; +static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K +static volatile uint8_t rstop = 0; +static volatile bool cancelled = false; +static volatile uint8_t curTransfer = 0; +static uint8_t nbTransfer = 0; +static uint16_t * tft_buffer; +static int tft_width; +static int tft_height; +static int tft_stride; + +#define DELAY_MASK 0x80 +PROGMEM static const uint8_t init_commands[] = { + 1+DELAY_MASK, TFT_SWRESET, 150, + 1+DELAY_MASK, TFT_SLPOUT, 255, + 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, + 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, + 1, TFT_INVON, + 1, TFT_DISPON, + 0 +}; + +// VGA constants and variables +// Objective: +// generates VGA signal fully in hardware with as little as possible CPU help + +// Principle: +// QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) +// 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate +// RGB out, combined to create 8bits(/12bits) output. + +// Note: +// - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels +// - experimental resolution: 352x240,352x480 +// - experimental resolution: 512x240,512x480 (not stable) +// - video memory is allocated using malloc in T4 heap +// - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing +// but tried to be compensated by pixel shifting +// - Default is 8bits RRRGGGBB (332) +// But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! +// - Only ok at 600MHz else some disturbances visible + + + +#define TOP_BORDER 40 +#define PIN_HBLANK 15 + +#define PIN_R_B2 33 +#define PIN_R_B1 4 +#define PIN_R_B0 3 +#define PIN_G_B2 2 +#define PIN_G_B1 13 +#define PIN_G_B0 11 +#define PIN_B_B1 12 +#define PIN_B_B0 10 + + +#define DMA_HACK 0x80 + +#define R16(rgb) ((rgb>>8)&0xf8) +#define G16(rgb) ((rgb>>3)&0xfc) +#define B16(rgb) ((rgb<<3)&0xf8) + +// VGA 640x480@60Hz +// Screen refresh rate 60 Hz +// Vertical refresh 31.46875 kHz +// Pixel freq. 25.175 MHz +// +// Visible area 640 25.422045680238 us +// Front porch 16 0.63555114200596 us +// Sync pulse 96 3.8133068520357 us +// Back porch 48 1.9066534260179 us +// Whole line 800 31.777557100298 us + +#define frame_freq 60.0 // Hz +#define line_freq 31.46875 // KHz +#define pix_freq (line_freq*800) // KHz (25.175 MHz) + +// pix_period = 39.7ns +// H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) +#define frontporch_pix 20 //16 +#define backporch_pix 44 //48 + +// Flexio Clock +// PLL3 SW CLOCK (3) => 480 MHz +// PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) +#define FLEXIO_CLK_SEL_PLL3 3 +#define FLEXIO_CLK_SEL_PLL5 2 + +/* Set video PLL */ +// There are /1, /2, /4, /8, /16 post dividers for the Video PLL. +// The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, +// and CCM_ANALOG_MISC2 register sets according to the following equation. +// PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + +// nfact: +// This field controls the PLL loop divider. +// Valid range for DIV_SELECT divider value: 27~54. + +#define POST_DIV_SELECT 2 + +// Full buffer including back/front porch +static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; +static uint32_t dstbuffer __attribute__((aligned(32))); + +// Visible vuffer +static vga_pixel * vga_buffer; +static int vga_width; +static int vga_height; +static int vga_stride; + +static int maxpixperline; +static int left_border; +static int right_border; +static int line_double; +static int pix_shift; +static int ref_div_select; +static int ref_freq_num; +static int ref_freq_denom; +static int ref_pix_shift; +static int combine_shiftreg; + +#ifdef DEBUG +static uint32_t ISRTicks_prev = 0; +volatile uint32_t ISRTicks = 0; +#endif + +uint8_t T4_DSP::_rst; +uint8_t T4_DSP::_cs; +uint8_t T4_DSP::_dc; +uint8_t T4_DSP::_mosi; +uint8_t T4_DSP::_sclk; +uint8_t T4_DSP::_vsync_pin = -1; +DMAChannel T4_DSP::flexio1DMA; +DMAChannel T4_DSP::flexio2DMA; + +static volatile uint32_t VSYNC = 0; +static volatile uint32_t currentLine=0; +#define NOP asm volatile("nop\n\t"); +static gfx_mode_t gfxmode = MODE_UNDEFINED; + + +FASTRUN void T4_DSP::TFT_isr(void) { + dmatx.clearInterrupt(); + curTransfer++; + if (curTransfer >= nbTransfer) { + curTransfer = 0; + if (cancelled) { + dmatx.disable(); + rstop = 1; + } + } + arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); +} + +FASTRUN void T4_DSP::QT3_isr(void) { + TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); + TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); + + cli(); + + // V-PULSE + if (currentLine > 0) { + digitalWrite(_vsync_pin, 1); + VSYNC = 0; + } else { + digitalWrite(_vsync_pin, 0); + VSYNC = 1; + } + + currentLine++; + currentLine = currentLine % 525; + + + uint32_t y = (currentLine - TOP_BORDER) >> line_double; + // Visible area + + if (y >= 0 && y < vga_height) { + // Disable DMAs + //DMA_CERQ = flexio2DMA.channel; + //DMA_CERQ = flexio1DMA.channel; + + // Setup source adress + // Aligned 32 bits copy + unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; + flexio2DMA.TCD->SADDR = p; + if (pix_shift & DMA_HACK) + { + // Unaligned copy + uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; + flexio1DMA.TCD->SADDR = p2; + } + else { + p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 + flexio1DMA.TCD->SADDR = p; + } + + // Enable DMAs + //flexio2DMA.enable(); + //flexio1DMA.enable(); + DMA_SERQ = flexio2DMA.channel; + DMA_SERQ = flexio1DMA.channel; + arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); + } + sei(); + +#ifdef DEBUG + ISRTicks++; +#endif + asm volatile("dsb"); +} + +static void setDmaStruct() { + uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; + uint16_t * fb = (uint16_t*)malloc(remaining); + tft_buffer = fb; + tft_width = TFT_WIDTH; + tft_height = TFT_HEIGHT; + tft_stride = TFT_WIDTH; + uint16_t col=RGBVAL16(0x00,0x00,0x00); + int i=0; + while (remaining > 0) { + int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); + blocks[i] = fb; + for (int j=0;jATTR_DST = 1; + dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); + dmasettings[i].interruptAtCompletion(); + fb += len/2; + remaining -= len; + i++; + } + dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); + nbTransfer = i; +} + +static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 +{ +//if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; + CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE + | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 + | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); + CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; + CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock + const int div_post_pll = 1; // other values: 2,4 + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass +} + +T4_DSP::T4_DSP() +{ + _cs = TFT_CS; + _dc = TFT_DC; + _rst = TFT_RST; + _mosi = TFT_MOSI; + _sclk = TFT_SCLK; + pinMode(_dc, OUTPUT); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, 1); + digitalWrite(_dc, 1); + _vsync_pin = 8; +} + + +void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { + int dx=0; + int dy=0; + digitalWrite(_dc, 0); + SPI.transfer(TFT_CASET); + digitalWrite(_dc, 1); + SPI.transfer16(x1+dx); + digitalWrite(_dc, 1); + SPI.transfer16(x2+dx); + digitalWrite(_dc, 0); + SPI.transfer(TFT_PASET); + digitalWrite(_dc, 1); + SPI.transfer16(y1+dy); + digitalWrite(_dc, 1); + SPI.transfer16(y2+dy); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + return; +} + +void T4_DSP::tft_setup(bool isST) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + // RESET if reset pin defined + if (_rst != 0xff) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + const uint8_t *addr = init_commands; + uint8_t count; + digitalWrite(_cs, 0); + while (count = *addr++) { + uint8_t command = *addr++; + if ( (command == TFT_INVON) && (!isST) ) { + // Skip TFT_INVON for ILI + } + else { + digitalWrite(_dc, 0); // command + SPI.transfer(command); + uint16_t ms = count & DELAY_MASK; + count &= ~DELAY_MASK; + while (--count > 0) { // data + uint8_t data = *addr++; + if ( (command == TFT_MADCTL) && (isST) ) { + data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; + } + digitalWrite(_dc, 1); + SPI.transfer(data); + } + if (ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + digitalWrite(_cs, 1); + SPI.endTransaction(); + delay(2); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + } + } + } + digitalWrite(_cs, 1); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + SPI.endTransaction(); + /* + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_dc, 0); + digitalWrite(_cs, 0); + SPI.transfer(TFT_MADCTL); + digitalWrite(_dc, 1); + SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); + // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); + digitalWrite(_cs, 1); + SPI.endTransaction(); + */ + cancelled = false; +} + +// display VGA image +gfx_error_t T4_DSP::begin(gfx_mode_t mode) +{ + uint32_t flexio_clock_div; + combine_shiftreg = 0; +// int div_select = 49; +// int num = 135; +// int denom = 100; + int div_select = 20; + int num = 9800; + int denom = 10000; + int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; + int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; + set_videoClock(div_select,num,denom,true); + +#ifdef DEBUG + Serial.println(mode); + Serial.println("mode"); +#endif + + switch(mode) + { + case MODE_TFTILI_320x240: +#ifdef DEBUG + Serial.println("TFTILI_320x240"); +#endif + tft_setup(false); + gfxmode = mode; + break; + case MODE_TFTST_320x240: +#ifdef DEBUG + Serial.println("TFTST_320x240"); +#endif + tft_setup(true); + gfxmode = mode; + break; + + case MODE_VGA_320x240: +#ifdef DEBUG + Serial.println("VGA_320x240"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_320x480: +#ifdef DEBUG + Serial.println("VGA_320x480"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_640x240: +#ifdef DEBUG + Serial.println("VGA_640x240"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/pix_freq; + line_double = 1; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_640x480: +#ifdef DEBUG + Serial.println("VGA_640x480"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = (flexio_freq/pix_freq); + line_double = 0; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_512x240: +#ifdef DEBUG + Serial.println("VGA_512x240"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 1; + pix_shift = 0; + break; + + case MODE_VGA_512x480: +#ifdef DEBUG + Serial.println("VGA_512x480"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 0; + pix_shift = 0; + break; + + case MODE_VGA_352x240: +#ifdef DEBUG + Serial.println("VGA_352x240"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_352x480: +#ifdef DEBUG + Serial.println("VGA_352x480"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + } + + if (mode >= MODE_VGA_320x240) + { + if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { + fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); + digitalWrite(_cs, 0); + digitalWrite(_dc, 0); + SPI.transfer(TFT_DISPOFF); + digitalWrite(_cs, 1); + delay(20); + digitalWrite(_cs, 0); + digitalWrite(_cs, 1); + } + gfxmode = mode; + + maxpixperline = vga_stride; + // Save param for tweek adjustment + ref_div_select = div_select; + ref_freq_num = num; + ref_freq_denom = denom; + ref_pix_shift = pix_shift; + +#ifdef DEBUG + Serial.println("frequency"); + Serial.println(flexio_freq); + Serial.println("div"); + Serial.println(flexio_freq/pix_freq); +#endif + + pinMode(_vsync_pin, OUTPUT); + pinMode(PIN_HBLANK, OUTPUT); + + /* Basic pin setup FlexIO1 */ + pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 + pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 + pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 + pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 + /* Basic pin setup FlexIO2 */ + pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 + pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 + pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 + pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 + + /* High speed and drive strength configuration */ + *(portControlRegister(PIN_G_B2)) = 0xFF; + *(portControlRegister(PIN_R_B0)) = 0xFF; + *(portControlRegister(PIN_R_B1)) = 0xFF; + *(portControlRegister(PIN_R_B2)) = 0xFF; + *(portControlRegister(PIN_B_B0)) = 0xFF; + *(portControlRegister(PIN_B_B1)) = 0xFF; + *(portControlRegister(PIN_G_B0)) = 0xFF; + *(portControlRegister(PIN_G_B1)) = 0xFF; + + /* Set clock for FlexIO1 and FlexIO2 */ + CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) + | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); + CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) + | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); + + + /* Set up pin mux FlexIO1 */ + *(portConfigRegister(PIN_G_B2)) = 0x14; + *(portConfigRegister(PIN_R_B0)) = 0x14; + *(portConfigRegister(PIN_R_B1)) = 0x14; + *(portConfigRegister(PIN_R_B2)) = 0x14; + /* Set up pin mux FlexIO2 */ + *(portConfigRegister(PIN_B_B0)) = 0x14; + *(portConfigRegister(PIN_B_B1)) = 0x14; + *(portConfigRegister(PIN_G_B0)) = 0x14; + *(portConfigRegister(PIN_G_B1)) = 0x14; + + /* Enable the clock */ + CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + /* Enable the FlexIO with fast access */ + FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + + uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; + uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; + + /* Shifter 0 registers for FlexIO2 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 + inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter + stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled + startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable + timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 + timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock + pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output + pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity + shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode + /* Shifter 0 registers for FlexIO1 */ + FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + /* Shifter 0 registers for FlexIO1 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 + FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + if (combine_shiftreg) { + pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled + FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + } + /* Timer 0 registers for FlexIO2 */ + timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset + timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output + timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset + timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare + timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert + stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled + startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled + if (combine_shiftreg) { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag + } + else { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag + } + triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low + triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected + pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled + //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 + //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high + timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode + // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) + + int shifts_per_transfer; + if (combine_shiftreg) { + shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 + } + else { + shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 + } + FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); + /* Timer 0 registers for FlexIO1 */ + FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); +#ifdef DEBUG + Serial.println("FlexIO setup complete"); +#endif + + /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ + if (combine_shiftreg) { + FLEXIO2_SHIFTSDEN |= (1<<1); + FLEXIO1_SHIFTSDEN |= (1<<1); + } + else { + FLEXIO2_SHIFTSDEN |= (1<<0); + FLEXIO1_SHIFTSDEN |= (1<<0); + } + /* Disable DMA channel so it doesn't start transferring yet */ + flexio1DMA.disable(); + flexio2DMA.disable(); + /* Set up DMA channel to use Shifter 0 trigger */ + flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); + flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); + + + if (combine_shiftreg) { + flexio2DMA.TCD->NBYTES = 8; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 8; + flexio2DMA.TCD->CITER = maxpixperline / 8; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + flexio1DMA.TCD->NBYTES = 8; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 8; + flexio1DMA.TCD->CITER = maxpixperline / 8; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Setup DMA2 Flexio2 copy + flexio2DMA.TCD->NBYTES = 4; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 4; + flexio2DMA.TCD->CITER = maxpixperline / 4; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + // Setup DMA1 Flexio1 copy + // Use pixel shift to avoid color smearing? + if (pix_shift & DMA_HACK) + { + if (pix_shift & 0x3 == 0) { + // Aligned 32 bits copy (32bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Unaligned (source) 32 bits copy (8bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 1; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion + } + } + else + { + // Aligned 32 bits copy + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + } + +#ifdef DEBUG + Serial.println("DMA setup complete"); +#endif + + // enable clocks for QTIMER3: generates the 15KHz for hsync + // Pulse: + // low : 3.8133 us => 569x6.7ns + // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) + // (OLD TEST) + // (4us low, 28us high => 32us) + // (597x6.7ns for 4us) + // (4179x6.7ns for 28us) + CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 + //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 + + #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz + #define MARGIN_D 1000 + + TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer + // Invert output pin as we want the interupt on rising edge + TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) + TMR3_CNTR3 = 0; + TMR3_LOAD3 = 0; + + /* Inverted timings */ + unsigned long long cpu_freq = F_CPU; + unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; + int rate2 = rate; + + int substract = 1; + if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { + substract=5; + rate2=1652; + } + + #ifdef DEBUG + Serial.print("MARGIN_N is: "); + Serial.println(rate2, DEC); + Serial.print("SUBSTRACT is: "); + Serial.println(substract, DEC); +#endif + TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; + TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; + /* + TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; + */ + TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on + TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), + // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) + //configure Teensy pin Compare output + IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 + attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function + NVIC_ENABLE_IRQ(IRQ_QTIMER3); +#ifdef DEBUG + Serial.println("QTIMER3 setup complete"); + Serial.print("V-PIN is "); + Serial.println(_vsync_pin); +#endif + + /* initialize gfx buffer */ + if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift + if (gfxbuffer == NULL) return(GFX_ERROR); +#ifdef DEBUG + Serial.println("Memory allocated"); +#endif + + memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); + vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; +#ifdef DEBUG + Serial.println(vga_stride); + Serial.println(vga_height); + Serial.println("Screen cleared"); +#endif + } + + return(GFX_OK); +} + +gfx_mode_t T4_DSP::getMode(void) +{ + return gfxmode; +} + +void T4_DSP::startRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + curTransfer = 0; + rstop = 0; + //dmatx.begin(true); + dmatx.attachInterrupt(TFT_isr); + setDmaStruct(); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + + digitalWrite(_cs, HIGH); + SPI.begin(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + + LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: + LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX + LPSPIP_TCR = 15; // Framesize 16 Bits + //LPSPIP_FCR = 0; // Fifo Watermark + LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable + LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: + dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); + + dmatx = dmasettings[0]; + digitalWrite(_cs, 0); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + dmatx.enable(); + } +} + + +void T4_DSP::stopRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + rstop = 1; + unsigned long m = millis(); + cancelled = true; + while (!rstop) { + if ((millis() - m) > 100) break; + delay(10); + asm volatile("wfi"); + }; + rstop = 0; + delay(50); + cancelled = false; + dmatx.detachInterrupt(); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + SPI.end(); +#ifdef ST7789 +// begin(gfxmode); +#endif + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + } +} + +int T4_DSP::get_frame_buffer_size(int *width, int *height) { + if (gfxmode < MODE_VGA_320x240) { + if (width != nullptr) *width = tft_width; + if (height != nullptr) *height = tft_height; + return tft_stride; + } + else { + if (width != nullptr) *width = vga_width; + if (height != nullptr) *height = vga_height; + return vga_stride; + } +} + +void T4_DSP::waitSync() +{ + if (gfxmode >= MODE_VGA_320x240) { + while (VSYNC == 0) {}; + } +} + +void T4_DSP::waitLine(int line) +{ + if (gfxmode >= MODE_VGA_320x240) { + while (currentLine != line) {}; + } +} + +/*********************************************************************************************** + No DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreenNoDma(uint16_t color) { + if (gfxmode < MODE_VGA_320x240) { + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + int i,j; + for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(arx, ary, arx+arw-1, ary+arh-1); + bitmap = bitmap + bmp_offy*w + bmp_offx; + for (int row=0;row> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + bits = *charpt++; + //digitalWrite(_dc, 1); + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + x +=8; + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + else { + drawText(x, y, text, fgcolor, bgcolor, doublesize); + } +} + + +/*********************************************************************************************** + DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreen(uint16_t color) { + int i,j; + if (gfxmode < MODE_VGA_320x240) { + for (j=0; j> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + dst=&tft_buffer[l*tft_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + x +=8; + } + } + else { + vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); + vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); + vga_pixel * dst; + while ((c = *text++)) { + const unsigned char * charpt=&font8x8[c][0]; + int l=y; + for (int i=0;i<8;i++) + { + unsigned char bits; + if (doublesize) { + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + x +=8; + } + } +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { + drawSprite(x,y,bitmap, 0,0,0,0); +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) +{ + int bmp_offx = 0; + int bmp_offy = 0; + uint16_t *bmp_ptr; + int w =*bitmap++; + int h = *bitmap++; + if ( (arw == 0) || (arh == 0) ) { + // no crop window + arx = x; + ary = y; + arw = w; + arh = h; + } + else { + if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + int l=ary; + bitmap = bitmap + bmp_offy*w + bmp_offx; + + if (gfxmode < MODE_VGA_320x240) { + for (int row=0;row tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]; + pos +=step; + } + #endif + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i 2) ) y += (tft_height-height)/2; + uint16_t * dst=&tft_buffer[y*tft_stride]; + if (width > tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]]; + pos +=step; + } +#endif + } + else if ((width*2) == tft_width) { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]]; + *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i tft_width) { + int step = ((width << 8)/tft_width); + int pos = 0; + for (int i=0; i> 8]]; + pos +=step; + } + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = pix; + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i +#include +#endif + +#include "platform_config.h" +#include "iopins.h" + + + +#ifndef TFT_WIDTH +#define TFT_WIDTH 320 +#endif +#define TFT_REALWIDTH 320 + +#ifndef TFT_HEIGHT +#define TFT_HEIGHT 240 +#endif +#define TFT_REALHEIGHT 240 + + +typedef enum gfx_mode_t +{ + MODE_UNDEFINED = 0, + MODE_TFTILI_320x240 = 1, + MODE_TFTST_320x240 = 2, + MODE_VGA_320x240 = 3, + MODE_VGA_320x480 = 4, + MODE_VGA_352x240 = 5, + MODE_VGA_352x480 = 6, + MODE_VGA_512x240 = 7, + MODE_VGA_512x480 = 8, + MODE_VGA_640x240 = 9, + MODE_VGA_640x480 = 10 +} gfx_mode_t; + +typedef enum gfx_error_t +{ + GFX_OK = 0, + GFX_ERROR = -1 +} gfx_error_t; + + +#ifdef __cplusplus + +class T4_DSP +{ + public: + T4_DSP(); + + gfx_error_t begin(gfx_mode_t mode); + gfx_mode_t getMode(void); + void startRefresh(void); + void stopRefresh(); + + int get_frame_buffer_size(int *width, int *height); + void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); + + // wait next Vsync + void waitSync(); + void waitLine(int line); + + // NoDMA functions + void fillScreenNoDma(uint16_t color); + void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + // DMA functions + void fillScreen(uint16_t color); + void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + void writeLine(int width, int height, int y, uint16_t *buf); + void writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + void writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16); + void writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + + protected: + static uint8_t _rst, _cs, _dc; + static uint8_t _mosi, _sclk; + static uint8_t _vsync_pin; + static DMAChannel flexio1DMA; + static DMAChannel flexio2DMA; + void tft_setup(bool isST); + static void TFT_isr(void); + static void QT3_isr(void); +}; + +#endif +#endif diff --git a/MCUME_teensy41/teecomputeraudiovideotest/teecomputeraudiovideotest.ino b/MCUME_teensy41/teecomputeraudiovideotest/teecomputeraudiovideotest.ino index 839945f..d39645a 100644 --- a/MCUME_teensy41/teecomputeraudiovideotest/teecomputeraudiovideotest.ino +++ b/MCUME_teensy41/teecomputeraudiovideotest/teecomputeraudiovideotest.ino @@ -1,73 +1,15 @@ -extern "C" { - #include "iopins.h" -} +#include "emuapi.h" +#include "iopins.h" - -#include "tft_t_dma.h" -TFT_T_DMA tft = TFT_T_DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, TFT_TOUCH_CS, TFT_TOUCH_INT); - -static IntervalTimer myTimer; -volatile boolean vbl=true; -static int skip=0; -static elapsedMicros tius; - -static void vblCount() { - if (vbl) { - vbl = false; - } else { - vbl = true; - } -} - -#ifdef HAS_SND - -#include "AudioPlaySystem.h" - -static AudioPlaySystem mymixer; - - -static void emu_sndInit() { - Serial.println("sound init"); - - mymixer.begin_audio(256, mymixer.snd_Mixer); - // sgtl5000_1.enable(); - // sgtl5000_1.volume(0.6); - mymixer.start(); -} - -static void emu_sndPlaySound(int chan, int volume, int freq) -{ - if (chan < 6) { - mymixer.sound(chan, freq, volume); - } - /* - Serial.print(chan); - Serial.print(":" ); - Serial.print(volume); - Serial.print(":" ); - Serial.println(freq); - */ -} - -static void emu_sndPlayBuzz(int size, int val) { - mymixer.buzz(size,val); - //Serial.print((val==1)?1:0); - //Serial.print(":"); - //Serial.println(size); -} -#endif +#include "t4_dsp.h" +extern T4_DSP tft; // **************************************************** // the setup() method runs once, when the sketch starts // **************************************************** void setup() { - tft.begin(); - tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); - tft.startDMA(); - myTimer.begin(vblCount, 20000); //to run every 20ms -#ifdef HAS_SND - emu_sndInit(); -#endif + emu_init(); + emu_start(20000,nullptr); } @@ -97,12 +39,13 @@ void loop(void) tft.fillScreen( RGBVAL16(colcomponent,0x00,0x00) ); colcomponent += 1; colcomponent &= 0xff; - volatile boolean vb=vbl; - while (vbl==vb) {}; + emu_DrawVsync(); notedelay += 1; notedelay &= 0x07; int note = notes[note_pos]; +#ifdef HAS_SND emu_sndPlaySound(1, notedelay<<4, note); +#endif if ( !notedelay ) { note_pos += 1; diff --git a/MCUME_teensy41/teecomputeraudiovideotest/tft_t_dma.cpp b/MCUME_teensy41/teecomputeraudiovideotest/tft_t_dma.cpp deleted file mode 100644 index 176962e..0000000 --- a/MCUME_teensy41/teecomputeraudiovideotest/tft_t_dma.cpp +++ /dev/null @@ -1,1243 +0,0 @@ -/* - Based on C64 ILI9341 dma driver from Frank Bösing, 2017 -*/ - -#include "TFT_T_DMA.h" - -#ifndef HAS_T4_VGA - -#include "font8x8.h" - -// LPSPI4 = SPI0 in Teensy 4.0 -// LPSPI3 = SPI1 in Teensy 4.0 -// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) -#ifdef TFTSPI1 -#define SPI SPI1 -#define LPSPIP_TDR LPSPI3_TDR -#define LPSPIP_CR LPSPI3_CR -#define LPSPIP_CFGR1 LPSPI3_CFGR1 -#define LPSPIP_TCR LPSPI3_TCR -#define LPSPIP_DER LPSPI3_DER -#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX -#else -#define LPSPIP_TDR LPSPI4_TDR -#define LPSPIP_CR LPSPI4_CR -#define LPSPIP_CFGR1 LPSPI4_CFGR1 -#define LPSPIP_TCR LPSPI4_TCR -#define LPSPIP_DER LPSPI4_DER -#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX -#endif - - -#define SPICLOCK 60000000 //144e6 //Just a number..max speed -#ifdef ILI9341 -#define SPI_MODE SPI_MODE0 -#endif -#ifdef ST7789 -#define SPI_MODE SPI_MODE2 -#endif - -// touch -#define SPI_SETTING SPISettings(2500000, MSBFIRST, SPI_MODE) -#define XPT2046_CFG_START _BV(7) -#define XPT2046_CFG_MUX(v) ((v&0b111) << (4)) -#define XPT2046_CFG_8BIT _BV(3) -#define XPT2046_CFG_12BIT (0) -#define XPT2046_CFG_SER _BV(2) -#define XPT2046_CFG_DFR (0) -#define XPT2046_CFG_PWR(v) ((v&0b11)) -#define XPT2046_MUX_Y 0b101 -#define XPT2046_MUX_X 0b001 -#define XPT2046_MUX_Z1 0b011 -#define XPT2046_MUX_Z2 0b100 - - -#ifdef TFT_STATICFB -static uint16_t fb0[LINES_PER_BLOCK*TFT_WIDTH]; -static uint16_t fb1[LINES_PER_BLOCK*TFT_WIDTH]; -static uint16_t fb2[LINES_PER_BLOCK*TFT_WIDTH]; -static uint16_t fb3[(TFT_HEIGHT-3*LINES_PER_BLOCK)*TFT_WIDTH]; -static uint16_t * blocks[NR_OF_BLOCK]={fb0,fb1,fb2,fb3}; -#else -static uint16_t * blocks[NR_OF_BLOCK]; -#endif - - -static DMASetting dmasettings[SCREEN_DMA_NUM_SETTINGS]; -static DMAChannel dmatx;//(false); -static volatile uint8_t rstop = 0; -static volatile bool cancelled = false; -static volatile uint8_t curTransfer = 0; -static uint8_t nbTransfer = 0; - - -PROGMEM static const uint8_t init_commands[] = { -#ifdef ILI9341 - 4, 0xEF, 0x03, 0x80, 0x02, - 4, 0xCF, 0x00, 0XC1, 0X30, - 5, 0xED, 0x64, 0x03, 0X12, 0X81, - 4, 0xE8, 0x85, 0x00, 0x78, - 6, 0xCB, 0x39, 0x2C, 0x00, 0x34, 0x02, - 2, 0xF7, 0x20, - 3, 0xEA, 0x00, 0x00, - 2, ILI9341_PWCTR1, 0x23, // Power control - 2, ILI9341_PWCTR2, 0x10, // Power control - 3, ILI9341_VMCTR1, 0x3e, 0x28, // VCM control - 2, ILI9341_VMCTR2, 0x86, // VCM control2 - 2, ILI9341_MADCTL, 0x48, // Memory Access Control - 2, ILI9341_PIXFMT, 0x55, - 3, ILI9341_FRMCTR1, 0x00, 0x18, - 4, ILI9341_DFUNCTR, 0x08, 0x82, 0x27, // Display Function Control - 2, 0xF2, 0x00, // Gamma Function Disable - 2, ILI9341_GAMMASET, 0x01, // Gamma curve selected - 16, ILI9341_GMCTRP1, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, - 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, // Set Gamma - 16, ILI9341_GMCTRN1, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, - 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, // Set Gamma -// 3, 0xb1, 0x00, 0x1f, // FrameRate Control 61Hz - 3, 0xb1, 0x00, 0x10, // FrameRate Control 119Hz - 2, ILI9341_MADCTL, ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR, - 0 -#endif -#ifdef ST7789 -#define DELAY 0x80 - 9, // 9 commands in list: - ST7735_SWRESET, DELAY, // 1: Software reset, no args, w/delay - 150, // 150 ms delay - ST7735_SLPOUT , DELAY, // 2: Out of sleep mode, no args, w/delay - 255, // 255 = 500 ms delay - ST7735_COLMOD , 1+DELAY, // 3: Set color mode, 1 arg + delay: - 0x55, // 16-bit color - 10, // 10 ms delay - ST7735_MADCTL , 1 , // 4: Memory access ctrl (directions), 1 arg: - 0x08, // Row addr/col addr, bottom to top refresh - ST7735_CASET , 4 , // 5: Column addr set, 4 args, no delay: - 0x00, - 0x00, // XSTART = 0 - 0x00, - 240, // XEND = 240 - ST7735_RASET , 4 , // 6: Row addr set, 4 args, no delay: - 0x00, - 0x00, // YSTART = 0 - 320>>8, - 320 & 0xFF, // YEND = 320 - ST7735_INVON , DELAY, // 7: hack - 10, - ST7735_NORON , DELAY, // 8: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 9: Main screen turn on, no args, w/delay - 255 -#endif -}; - -static void dmaInterrupt() { - dmatx.clearInterrupt(); - curTransfer++; - if (curTransfer >= nbTransfer) { - curTransfer = 0; - if (cancelled) { - dmatx.disable(); - rstop = 1; - } - } - arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2); -} - -static void setDmaStruct() { - uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; - int i=0; - uint16_t col=RGBVAL16(0x00,0x00,0x00);; - while (remaining > 0) { - uint16_t * fb = blocks[i]; - int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining); -#ifdef TFT_DEBUG - Serial.println((unsigned long)blocks[i]); - Serial.println(remaining); -#endif - switch (i) { - case 0: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb0[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0x00); -#endif - break; - case 1: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb1[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0xff); -#endif - break; - case 2: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb2[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0x00,0xff); -#endif - break; - case 3: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb3[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0xff,0x00,0xff); -#endif - break; - } - blocks[i] = fb; - if (blocks[i] == 0) { - Serial.print("ILI9341 allocaltion failed for block "); - Serial.println(i); - delay(10000); - } - - for (int j=0;jATTR_DST = 1; - dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); - dmasettings[i].interruptAtCompletion(); - remaining -= len; - i++; - } - dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); - nbTransfer = i; -#ifdef TFT_DEBUG - Serial.println(nbTransfer); -#endif -} - - -TFT_T_DMA::TFT_T_DMA(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso, uint8_t touch_cs, uint8_t touch_irq) -{ - _cs = cs; - _dc = dc; - _rst = rst; - _mosi = mosi; - _sclk = sclk; - _miso = miso; - pinMode(_dc, OUTPUT); - pinMode(_cs, OUTPUT); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); - if ( (touch_cs != 255) && (touch_irq != 255) ) { - _touch_irq = touch_irq; - _touch_cs = touch_cs; - pinMode(_touch_cs, OUTPUT); - pinMode(touch_irq, INPUT_PULLUP); - digitalWrite(_touch_cs, 1); - } -} - - -void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { - int dx=0; - int dy=0; -#ifdef ST7789 - if (TFT_REALWIDTH == TFT_REALHEIGHT) - { -#ifdef ROTATE_SCREEN - if (!flipped) { - dy += 80; - } -#else - if (flipped) { - dx += 80; - } -#endif - } -#endif - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - SPI.transfer16(x1+dx); - digitalWrite(_dc, 1); - SPI.transfer16(x2+dx); - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - digitalWrite(_dc, 1); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - return; - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - - SPI.transfer16(x1+dx); - SPI.transfer16(x2+dx); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - -void TFT_T_DMA::begin(void) { - SPI.setMOSI(_mosi); - SPI.setMISO(_miso); - SPI.setSCK(_sclk); - SPI.begin(); - - // Initialize display - if (_rst != 0xff) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - const uint8_t *addr = init_commands; - digitalWrite(_cs, 0); -#ifdef ILI9341 - while (1) { - uint8_t count = *addr++; - if (count-- == 0) break; - - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - - while (count-- > 0) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - } - - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(ILI9341_DISPON); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); -#endif -#ifdef ST7789 - uint8_t numCommands, numArgs; - uint16_t ms; - numCommands = *addr++; // Number of commands to follow - while(numCommands--) { // For each command... - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - numArgs = *addr++; // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs > 1) { // For each argument... - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - numArgs--; - } - - if (numArgs) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - if(ms) { - ms = *addr++; // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - digitalWrite(_cs, 1); - SPI.endTransaction(); - delay(ms); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - } - } - digitalWrite(_cs, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - SPI.endTransaction(); - - cancelled = false; - -#ifdef FLIP_SCREEN - flipscreen(true); -#else - flipscreen(false); -#endif -#ifdef ST7789 - if (TFT_REALWIDTH != TFT_REALHEIGHT) - { - flipscreen(true); - } -#endif -}; - - - -void TFT_T_DMA::flipscreen(bool flip) -{ - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(TFT_MADCTL); - digitalWrite(_dc, 1); - if (flip) { - flipped=true; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB); -#endif -#endif - } - else { - flipped=false; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB); -#endif -#endif - } - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - -boolean TFT_T_DMA::isflipped(void) -{ - return(flipped); -} - - -#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) - - -void TFT_T_DMA::startDMA(void) { - curTransfer = 0; - rstop = 0; - //dmatx.begin(true); - dmatx.attachInterrupt(dmaInterrupt); - setDmaStruct(); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - - digitalWrite(_cs, HIGH); - SPI.begin(); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); - - - LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: - LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX - LPSPIP_TCR = 15; // Framesize 16 Bits - //LPSPIP_FCR = 0; // Fifo Watermark - LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable - LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: - dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); - - dmatx = dmasettings[0]; - digitalWrite(_cs, 0); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - dmatx.enable(); -} - - -void TFT_T_DMA::stopDMA(void) { - rstop = 0; - wait(); - delay(50); - cancelled = false; - dmatx.detachInterrupt(); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - SPI.end(); -#ifdef ST7789 - begin(); -#endif -#ifdef ILI9341 - SPI.begin(); - digitalWrite(_cs, 0); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - SPI.endTransaction(); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); -} - -void TFT_T_DMA::wait(void) { - rstop = 1; - unsigned long m = millis(); - cancelled = true; - while (!rstop) { - if ((millis() - m) > 100) break; - delay(10); - asm volatile("wfi"); - }; - rstop = 0; -} - -int TFT_T_DMA::get_frame_buffer_size(int *width, int *height){ - if (width != nullptr) *width = TFT_REALWIDTH; - if (height != nullptr) *height = TFT_REALHEIGHT; - return TFT_REALWIDTH; -} - - -/*********************************************************************************************** - Touch functions - ***********************************************************************************************/ -/* Code based on ... - * - * @file XPT2046.cpp - * @date 19.02.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the XPT2046 driver for Arduino. - */ - -#define ADC_MAX 0x0fff - -void TFT_T_DMA::enableTouchIrq() -{ - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 }; - SPI.transfer((void*)&buf[0],3); - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); -} - -//Default callibration for non flipped -#define TX_MIN 30 -#define TY_MIN 20 -#define TX_MAX 300 -#define TY_MAX 220 - -//Default callibration for flipped -#define TFX_MIN 20 -#define TFY_MIN 25 -#define TFX_MAX 288 -#define TFY_MAX 221 - -static uint16_t txMin; -static uint16_t tyMin; -static uint16_t txMax; -static uint16_t tyMax; - - -void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { - if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) { - txMin = xMin; - tyMin = yMin; - txMax = xMax; - tyMax = yMax; - } - else { - if (flipped) { - txMin = TFX_MIN; - tyMin = TFY_MIN; - txMax = TFX_MAX; - tyMax = TFY_MAX; - } - else { - txMin = TX_MIN; - tyMin = TY_MIN; - txMax = TX_MAX; - tyMax = TY_MAX; - } - } -} - - -void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - if ( TOUCH_ENABLED() ) { - uint16_t x = 0; - uint16_t y = 0; - uint16_t z1 = 0; - uint16_t z2 = 0; - uint8_t i = 0; - int16_t xraw=0, yraw=0; - - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - - for(; i < 15; i++) { - // SPI requirer 32bit aliment - uint8_t buf[12] = { - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00 - }; - SPI.transfer(&buf[0], &buf[0], 12); - y += (buf[1] << 8 | buf[2])>>3; - x += (buf[4] << 8 | buf[5])>>3; - z1 += (buf[7] << 8 | buf[8])>>3; - z2 += (buf[10] << 8 | buf[11])>>3; - } - enableTouchIrq(); - - if(i == 0) { - *oX = 0; - *oY = 0; - *oZ = 0; - } - else { - x /= i; - y /= i; - z1 /= i; - z2 /= i; - } - - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); - int z = z1 + ADC_MAX - z2; - if (flipped) { - xraw = x; - yraw = y; - } else { - xraw = ADC_MAX - x; - yraw = ADC_MAX - y; - } - xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1); - yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1); - - *oX = xraw; - *oY = yraw; - *oZ = z; - } - else - { - *oX = 0; - *oY = 0; - *oZ = 0; - } -} - -void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - readRaw(oX,oY,oZ); - // callibrate ... - if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin); - if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin); - //Serial.print(*oX); - //Serial.print(" "); - //Serial.println(*oY); -} - - -/*********************************************************************************************** - No DMA functions - ***********************************************************************************************/ -void TFT_T_DMA::fillScreenNoDma(uint16_t color) { - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - int i,j; - for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(arx, ary, arx+arw-1, ary+arh-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - bits = *charpt++; - //digitalWrite(_dc, 1); - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - x +=8; -#ifdef ILI9341 - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); -#endif - digitalWrite(_cs, 1); - SPI.endTransaction(); - } - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - - - -/*********************************************************************************************** - DMA functions - ***********************************************************************************************/ -uint16_t * TFT_T_DMA::getLineBuffer(int j) -{ - uint16_t * block=blocks[j>>6]; - return(&block[(j&0x3F)*TFT_REALWIDTH]); -} - -void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) { - uint8_t *buffer=buf; - uint8_t *src; - - int i,j,y=0; - if (width*2 <= TFT_REALWIDTH) { - for (j=0; j>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH]; - for (i=0; i>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x]; - for (i=0; i>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - block=blocks[l>>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt++; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - x +=8; - } -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { - drawSprite(x,y,bitmap, 0,0,0,0); -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) -{ - int bmp_offx = 0; - int bmp_offy = 0; - uint16_t *bmp_ptr; - - int w =*bitmap++; - int h = *bitmap++; - - - if ( (arw == 0) || (arh == 0) ) { - // no crop window - arx = x; - ary = y; - arw = w; - arh = h; - } - else { - if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - int l=ary; - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx]; - bmp_ptr = (uint16_t*)bitmap; - for (int col=0;col -#include -#include -#endif - -#include "tft_t_dma_config.h" - -#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) -#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define R16(rgb) ((rgb>>8)&0xf8) -#define G16(rgb) ((rgb>>3)&0xfc) -#define B16(rgb) ((rgb<<3)&0xf8) - -#define PAL_COLOR_MASK 0xff - -#ifdef LOHRES -#define TFT_WIDTH 240 -#define TFT_REALWIDTH 240 -#else -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 -#endif -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - -//#define WIDTH 272 -//#define HEIGHT 228 - -#define LINES_PER_BLOCK 64 -#define NR_OF_BLOCK 4 -#define SCREEN_DMA_NUM_SETTINGS NR_OF_BLOCK - - -#ifdef ILI9341 - -#define ILI9341_NOP 0x00 -#define ILI9341_SWRESET 0x01 -#define ILI9341_RDDID 0x04 -#define ILI9341_RDDST 0x09 - -#define ILI9341_SLPIN 0x10 -#define ILI9341_SLPOUT 0x11 -#define ILI9341_PTLON 0x12 -#define ILI9341_NORON 0x13 - -#define ILI9341_RDMODE 0x0A -#define ILI9341_RDMADCTL 0x0B -#define ILI9341_RDPIXFMT 0x0C -#define ILI9341_RDIMGFMT 0x0D -#define ILI9341_RDSELFDIAG 0x0F - -#define ILI9341_INVOFF 0x20 -#define ILI9341_INVON 0x21 -#define ILI9341_GAMMASET 0x26 -#define ILI9341_DISPOFF 0x28 -#define ILI9341_DISPON 0x29 - -#define ILI9341_CASET 0x2A -#define ILI9341_PASET 0x2B -#define ILI9341_RAMWR 0x2C -#define ILI9341_RAMRD 0x2E - -#define ILI9341_PTLAR 0x30 -#define ILI9341_MADCTL 0x36 -#define ILI9341_VSCRSADD 0x37 -#define ILI9341_PIXFMT 0x3A - -#define ILI9341_FRMCTR1 0xB1 -#define ILI9341_FRMCTR2 0xB2 -#define ILI9341_FRMCTR3 0xB3 -#define ILI9341_INVCTR 0xB4 -#define ILI9341_DFUNCTR 0xB6 - -#define ILI9341_PWCTR1 0xC0 -#define ILI9341_PWCTR2 0xC1 -#define ILI9341_PWCTR3 0xC2 -#define ILI9341_PWCTR4 0xC3 -#define ILI9341_PWCTR5 0xC4 -#define ILI9341_VMCTR1 0xC5 -#define ILI9341_VMCTR2 0xC7 - -#define ILI9341_RDID1 0xDA -#define ILI9341_RDID2 0xDB -#define ILI9341_RDID3 0xDC -#define ILI9341_RDID4 0xDD - -#define ILI9341_GMCTRP1 0xE0 -#define ILI9341_GMCTRN1 0xE1 - -#define ILI9341_MADCTL_MY 0x80 -#define ILI9341_MADCTL_MX 0x40 -#define ILI9341_MADCTL_MV 0x20 -#define ILI9341_MADCTL_ML 0x10 -#define ILI9341_MADCTL_RGB 0x00 -#define ILI9341_MADCTL_BGR 0x08 -#define ILI9341_MADCTL_MH 0x04 - -#define TFT_CASET ILI9341_CASET -#define TFT_PASET ILI9341_PASET -#define TFT_RAMWR ILI9341_RAMWR -#define TFT_MADCTL ILI9341_MADCTL - -#endif - - -#ifdef ST7789 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_RGB 0x00 -#define ST77XX_MADCTL_BGR 0x08 -#define ST77XX_MADCTL_MH 0x04 - -#define TFT_CASET ST7735_CASET -#define TFT_PASET ST7735_RASET -#define TFT_RAMWR ST7735_RAMWR -#define TFT_MADCTL ST7735_MADCTL - -#endif - - - -#ifdef __cplusplus - -class TFT_T_DMA -{ - public: - TFT_T_DMA(uint8_t _CS, uint8_t _DC, uint8_t _RST = 255, uint8_t _MOSI=11, uint8_t _SCLK=13, uint8_t _MISO=12, uint8_t touch_cs=38, uint8_t touch_irq=37); - - void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); - void begin(void); - void flipscreen(bool flip); - boolean isflipped(void); - void startDMA(void); - void stopDMA(); - int get_frame_buffer_size(int *width, int *height); - - // Touch screen functions - #define TOUCH_ENABLED() ((_touch_cs != 255) && (_touch_irq != 255)) - bool isTouching(void) { return ((!TOUCH_ENABLED())?false:(digitalRead(_touch_irq) == LOW)); } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax); - - // NoDMA functions - void writeScreenNoDma(const uint16_t *pcolors); - void fillScreenNoDma(uint16_t color); - void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - // DMA functions - uint16_t * getLineBuffer(int j); - void writeScreen(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int y, uint16_t *buf); - void fillScreen(uint16_t color); - void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - protected: - uint8_t _rst, _cs, _dc; - uint8_t _miso, _mosi, _sclk; - uint8_t _touch_irq=255, _touch_cs=255; - bool flipped=false; - - void wait(void); - void enableTouchIrq(); -}; - -#endif -#endif - - diff --git a/MCUME_teensy41/teecomputeraudiovideotest/tft_t_dma_config.h b/MCUME_teensy41/teecomputeraudiovideotest/tft_t_dma_config.h deleted file mode 100644 index 354cf74..0000000 --- a/MCUME_teensy41/teecomputeraudiovideotest/tft_t_dma_config.h +++ /dev/null @@ -1,14 +0,0 @@ -#include "platform_config.h" - -//#define ST7789 1 -//#define ILI9341 1 - -#define TFT_LINEARINT 1 -#define LINEARINT_HACK 1 - -//#define FLIP_SCREEN 1 -//#define TFT_DEBUG 1 -#if defined(__IMXRT1052__) || defined(__IMXRT1062__) -//#define TFT_STATICFB 1 -#endif - diff --git a/MCUME_teensy41/teecomputerkeytest/AudioPlaySystem.cpp b/MCUME_teensy41/teecomputerkeytest/AudioPlaySystem.cpp index dff01de..85da04d 100644 --- a/MCUME_teensy41/teecomputerkeytest/AudioPlaySystem.cpp +++ b/MCUME_teensy41/teecomputerkeytest/AudioPlaySystem.cpp @@ -176,7 +176,6 @@ void AudioPlaySystem::step(void) { } -#ifndef HAS_T4_VGA /******************************************************************* Experimental I2S interrupt based sound driver for PCM51xx !!! *******************************************************************/ @@ -263,7 +262,57 @@ FLASHMEM static void config_sai1() I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE ;//<-- not using DMA */; } +FLASHMEM static void config_pt8211() +{ + CCM_CCGR5 |= CCM_CCGR5_SAI1(CCM_CCGR_ON); + double fs = AUDIO_SAMPLE_RATE_EXACT; + // PLL between 27*24 = 648MHz und 54*24=1296MHz + int n1 = 4; //SAI prescaler 4 => (n1*n2) = multiple of 4 + int n2 = 1 + (24000000 * 27) / (fs * 256 * n1); + double C = (fs * 256 * n1 * n2) / 24000000; + int c0 = C; + int c2 = 10000; + int c1 = C * c2 - (c0 * c2); + set_audioClock(c0, c1, c2, true); + // clear SAI1_CLK register locations + CCM_CSCMR1 = (CCM_CSCMR1 & ~(CCM_CSCMR1_SAI1_CLK_SEL_MASK)) + | CCM_CSCMR1_SAI1_CLK_SEL(2); // &0x03 // (0,1,2): PLL3PFD0, PLL5, PLL4 + + //n1 = n1 / 2; //Double Speed for TDM + + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_SAI1_CLK_PRED_MASK | CCM_CS1CDR_SAI1_CLK_PODF_MASK)) + | CCM_CS1CDR_SAI1_CLK_PRED(n1 - 1) // &0x07 + | CCM_CS1CDR_SAI1_CLK_PODF(n2 - 1); // &0x3f + + IOMUXC_GPR_GPR1 = (IOMUXC_GPR_GPR1 & ~(IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL_MASK)) + | (IOMUXC_GPR_GPR1_SAI1_MCLK_DIR | IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL(0)); //Select MCLK + + + // configure transmitter + int rsync = 0; + int tsync = 1; + + I2S1_TMR = 0; + I2S1_TCR1 = I2S_TCR1_RFW(0); + I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_BCP | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(1); + I2S1_TCR3 = I2S_TCR3_TCE; + I2S1_TCR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(15) | I2S_TCR4_MF | I2S_TCR4_FSD /*| I2S_TCR4_FSE*/ | I2S_TCR4_FSP ; //PT8211 + I2S1_TCR5 = I2S_TCR5_WNW(15) | I2S_TCR5_W0W(15) | I2S_TCR5_FBT(15); + + I2S1_RMR = 0; + I2S1_RCR1 = I2S_RCR1_RFW(0); + I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_RCR2_BCP | I2S_RCR2_MSEL(1)| I2S_RCR2_BCD | I2S_RCR2_DIV(1) ; + I2S1_RCR3 = I2S_RCR3_RCE; + I2S1_RCR4 = I2S_RCR4_FRSZ(1) | I2S_RCR4_SYWD(15) | I2S_RCR4_MF /*| I2S_RCR4_FSE*/ | I2S_RCR4_FSP | I2S_RCR4_FSD; //PT8211 + I2S1_RCR5 = I2S_RCR5_WNW(15) | I2S_RCR5_W0W(15) | I2S_RCR5_FBT(15); + + CORE_PIN21_CONFIG = 3; // RX_BCLK + CORE_PIN20_CONFIG = 3; // RX_SYNC + CORE_PIN7_CONFIG = 3; // TX_DATA0 + I2S1_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE; + I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE ;//<-- not using DMA */; +} //DMAMEM __attribute__((aligned(32))) static uint32_t i2s_tx[1024]; @@ -277,7 +326,6 @@ static uint32_t * i2s_tx_buffer __attribute__((aligned(32))); static uint16_t * i2s_tx_buffer16; static uint16_t * txreg = (uint16_t *)((uint32_t)&I2S1_TDR0 + 2); - FASTRUN void AudioPlaySystem::AUDIO_isr() { *txreg = i2s_tx_buffer16[cnt]; @@ -335,7 +383,14 @@ FLASHMEM void AudioPlaySystem::begin_audio(int samplesize, void (*callback)(shor sampleBufferSize = samplesize; +#ifdef PT8211 + txreg = (uint16_t *)((uint32_t)&I2S1_TDR0); + config_pt8211(); +#else + txreg = (uint16_t *)((uint32_t)&I2S1_TDR0 + 2); config_sai1(); +#endif + attachInterruptVector(IRQ_SAI1, AUDIO_isr); NVIC_ENABLE_IRQ(IRQ_SAI1); NVIC_SET_PRIORITY(IRQ_QTIMER3, 0); // 0 highest priority, 255 = lowest priority @@ -358,4 +413,3 @@ FLASHMEM void AudioPlaySystem::end_audio() } #endif -#endif diff --git a/MCUME_teensy41/teecomputerkeytest/AudioPlaySystem.h b/MCUME_teensy41/teecomputerkeytest/AudioPlaySystem.h index fb22cdc..6d2e23b 100644 --- a/MCUME_teensy41/teecomputerkeytest/AudioPlaySystem.h +++ b/MCUME_teensy41/teecomputerkeytest/AudioPlaySystem.h @@ -19,13 +19,10 @@ public: void buzz(int size, int val); void step(void); static void snd_Mixer(short * stream, int len ); -#ifndef HAS_T4_VGA void begin_audio(int samplesize, void (*callback)(short * stream, int len)); void end_audio(); static void AUDIO_isr(void); - static void SOFTWARE_isr(void); -#endif - + static void SOFTWARE_isr(void); }; diff --git a/MCUME_teensy41/teecomputerkeytest/emuapi.cpp b/MCUME_teensy41/teecomputerkeytest/emuapi.cpp index c367cb0..e128cca 100644 --- a/MCUME_teensy41/teecomputerkeytest/emuapi.cpp +++ b/MCUME_teensy41/teecomputerkeytest/emuapi.cpp @@ -5,25 +5,31 @@ extern "C" { #include "iopins.h" } -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#else -#include "tft_t_dma.h" -#endif +#include -#ifdef HAS_USBKEY +#ifdef HAS_USB #include "USBHost_t36.h" // Read this header first for key info USBHost myusb; USBHub hub1(myusb); +#ifdef HAS_USBKEY KeyboardController keyboard1(myusb); USBHIDParser hid1(myusb); MouseController mouse1(myusb); +#endif +#ifdef HAS_USBMIDI MIDIDevice midi1(myusb); #endif +#ifdef HAS_USBJOY +#define COUNT_JOYSTICKS 4 +JoystickController joysticks[COUNT_JOYSTICKS](myusb); +#endif +#endif static bool emu_writeConfig(void); static bool emu_readConfig(void); static bool emu_eraseConfig(void); +static bool emu_writeGfxConfig(char * display_type); +static int emu_readGfxConfig(void); static bool mouseDetected = false; static bool keyboardDetected = false; @@ -34,12 +40,13 @@ static File file; #define MAX_FILES 64 #define AUTORUN_FILENAME "autorun.txt" +#define GFX_CFG_FILENAME "gfxmode.txt" -#define MAX_FILENAME_SIZE 24 +#define MAX_FILENAME_SIZE 34 #define MAX_MENULINES 9 #define TEXT_HEIGHT 16 #define TEXT_WIDTH 8 -#define MENU_FILE_XOFFSET (6*TEXT_WIDTH) +#define MENU_FILE_XOFFSET (2*TEXT_WIDTH) #define MENU_FILE_YOFFSET (2*TEXT_HEIGHT) #define MENU_FILE_W (MAX_FILENAME_SIZE*TEXT_WIDTH) #define MENU_FILE_H (MAX_MENULINES*TEXT_HEIGHT) @@ -53,7 +60,8 @@ static File file; #define MENU_VGA_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) #define MENU_VGA_YOFFSET (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37) -extern TFT_T_DMA tft; +#include "t4_dsp.h" +T4_DSP tft; static int nbFiles=0; static int curFile=0; @@ -65,6 +73,8 @@ static char selected_filename[MAX_FILENAME_SIZE]=""; static char second_selected_filename[MAX_FILENAME_SIZE]=""; static bool menuRedraw=true; static bool autorun=false; +static bool vgahires=false; + static const unsigned short * keys; #ifdef TEECOMPUTER @@ -158,6 +168,29 @@ void emu_Free(void * pt) free(pt); } +#define SMEMPOOL (0x800000) +EXTMEM static unsigned char slowmem[SMEMPOOL]; +static int slowmempt = 0; + +void * emu_SMalloc(unsigned int size) +{ + void * mem = (void*)&slowmem[slowmempt]; + slowmempt += size; + + if ( slowmempt > SMEMPOOL ) { + mem = NULL; + emu_printf("failure to allocate slow"); + } + else { + emu_printf("could allocate slow static "); + emu_printf(size); + } + return mem; +} + +void emu_SFree(void * pt) +{ +} /******************************** * Input and keyboard ********************************/ @@ -329,6 +362,12 @@ int emu_ReadKeys(void) #endif if ( row & 0x02 ) retval |= MASK_JOY2_BTN; + +#ifdef EXTPAD + if ( sh_pressed ) retval |= MASK_KEY_USER3; + if ( fn_pressed ) retval |= MASK_KEY_USER1; + digitalWrite(KLED, 0); +#else // Handle LED flash uint32_t time_ms=millis(); if ((time_ms-last_t_ms) > 100) { @@ -412,8 +451,9 @@ int emu_ReadKeys(void) if ( key_fn ) retval |= MASK_KEY_USER2; if ( ( key_fn ) && (keymatrix[4] == 0x10 )) retval |= MASK_KEY_USER1; +#endif - if ( (key_fn) && (key_sh) ) + if ( (fn_pressed) && (sh_pressed) ) #else if ( ((retval & (MASK_KEY_USER1+MASK_KEY_USER2)) == (MASK_KEY_USER1+MASK_KEY_USER2)) || (retval & MASK_KEY_USER4 ) ) @@ -453,8 +493,10 @@ int emu_ReadKeys(void) while (true) { ; } -#endif +#endif } + + emu_GetJoystick(); return (retval); } @@ -607,7 +649,7 @@ int emu_setKeymap(int index) { } int emu_GetMouse(int *x, int *y, int *buts) { -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBKEY) if (mouse1.available()) { *buts = mouse1.getButtons(); *x = mouse1.getMouseX(); @@ -620,7 +662,23 @@ int emu_GetMouse(int *x, int *y, int *buts) { return 0; } -#ifdef HAS_USBKEY +int emu_GetJoystick(void) { +#if defined(HAS_USB) && (HAS_USBJOY) + for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) { + if (joysticks[joystick_index].available()) { + uint64_t axis_mask = joysticks[joystick_index].axisMask(); + uint64_t axis_changed_mask = joysticks[joystick_index].axisChangedMask(); + uint32_t buttons = joysticks[joystick_index].getButtons(); + Serial.printf("Joystick(%d): buttons = %x", joystick_index, buttons); + Serial.println(); + } + } + return 1; +#endif + return 0; +} + +#if defined(HAS_USB) && (HAS_USBKEY) void OnPress(auto key) { keyboardDetected = true; @@ -764,7 +822,7 @@ int emu_KeyboardDetected(void) { return (keyboardDetected?1:0); } -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) static unsigned char midiBuffer[16]; static unsigned char midiLastCmd=0; static int midiDataCnt=0; @@ -772,8 +830,7 @@ static int midiCmdNbParam=0; #endif void emu_MidiOnDataReceived(unsigned char value) { - -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) //Serial.println(value, HEX); //10000000 = 128 = note off //10010000 = 144 = note on @@ -941,6 +998,7 @@ void emu_MidiOnDataReceived(unsigned char value) { /******************************** * Menu file loader UI ********************************/ +#ifdef FILEBROWSER static int readNbFiles(void) { int totalFiles = 0; @@ -970,8 +1028,6 @@ static int readNbFiles(void) { return totalFiles; } - - void backgroundMenu(void) { menuRedraw=true; tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00)); @@ -981,11 +1037,13 @@ void backgroundMenu(void) { int handleMenu(uint16_t bClick) { if (autorun) { + toggleMenu(false); + menuRedraw=false; return (ACTION_RUN1); } int action = ACTION_NONE; - if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) ) { + if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) || ( bClick & MASK_KEY_USER2 ) ) { char newpath[MAX_FILENAME_PATH]; strcpy(newpath, selection); strcat(newpath, "/"); @@ -996,17 +1054,31 @@ int handleMenu(uint16_t bClick) File file = SD.open(selection); if (file.isDirectory()) { curFile = 0; - nbFiles = readNbFiles(); + nbFiles = readNbFiles(); + menuRedraw=true; } - else { - action = ACTION_RUN1; + else + { #ifdef TEECOMPUTER - if (key_extmode) { + if ( (key_extmode) || ( key_sh) ) { emu_writeConfig(); } + if ( tft.getMode() < MODE_VGA_320x240) { + if ( bClick & MASK_KEY_USER2 ) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + } + //emu_SwapJoysticks(0); #endif + toggleMenu(false); + menuRedraw=false; + return (ACTION_RUN1); } - menuRedraw=true; } else if ( bClick & MASK_KEY_USER1 ) { menuRedraw=true; @@ -1015,19 +1087,14 @@ int handleMenu(uint16_t bClick) strcat(second_selection, "/"); strcat(second_selection, second_selected_filename); action = ACTION_RUN2; - } - else if ( bClick & MASK_KEY_USER2 ) { - menuRedraw=true; - //action = ACTION_RUN3; - emu_SwapJoysticks(0); - } + } else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) { if (curFile!=0) { menuRedraw=true; curFile--; } } - else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { + else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { if ((curFile-9)>=0) { menuRedraw=true; curFile -= 9; @@ -1042,7 +1109,7 @@ int handleMenu(uint16_t bClick) menuRedraw=true; } } - else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { + else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { if ((curFile<(nbFiles-9)) && (nbFiles)) { curFile += 9; menuRedraw=true; @@ -1099,12 +1166,12 @@ int handleMenu(uint16_t bClick) return (action); } -bool menuActive(void) +int menuActive(void) { - return (menuOn); + return (menuOn?1:0); } -void toggleMenu(bool on) { +void toggleMenu(int on) { if (on) { menuOn=true; backgroundMenu(); @@ -1122,7 +1189,7 @@ char * menuSecondSelection(void) { return (second_selection); } - +#endif /******************************** * OSKB handling @@ -1140,8 +1207,9 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) char c[4] = {' ',0,' ',0}; const char * cpt = str; int i=0; - int fb_width,fb_height; - tft.get_frame_buffer_size(&fb_width, &fb_height); + int fb_width,fb_height,fbstride; + + fbstride = tft.get_frame_buffer_size(&fb_width, &fb_height); int ypos = (bottom?(fb_height-2*8):0); int line = row + (bottom?2:0); while ((c[1] = *cpt++)) @@ -1150,7 +1218,7 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0); else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff); if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff); - tft.drawTextNoDma(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); + tft.drawText(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); i++; } } @@ -1248,7 +1316,7 @@ int handleOSKB(void) { return retval; } -void toggleOSKB(bool forceon) { +void toggleOSKB(int forceon) { if (forceon) { oskbOn = true; drawOSKB(); @@ -1332,6 +1400,17 @@ int emu_FileRead(void * buf, int size, int handler) #endif } +int emu_FileWrite(void * buf, int size, int handler) +{ +// emu_printf("emu_FileWrite"); +// emu_printi(handler); +#ifdef HCFH + return (file.write(buf, size)); +#else + return (getFileHandler(handler).write(buf, size)); +#endif +} + int emu_FileGetc(int handler) { // emu_printf("FileGetc"); // emu_printi(handler); @@ -1404,6 +1483,9 @@ unsigned int emu_FileSize(const char * filepath) emu_printf(filesize); lofile.close(); } + else { + emu_printf("filesize failed"); + } return(filesize); } @@ -1489,6 +1571,48 @@ static bool emu_eraseConfig(void) SD.remove (ROMSDIR "/" AUTORUN_FILENAME); } +static bool emu_writeGfxConfig(char * display_type) +{ + bool retval = false; + SD.remove ("/" GFX_CFG_FILENAME); + if (strcmp(display_type, "VGA")) { + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(display_type, strlen(display_type)) != strlen(display_type)) { + emu_printf("GFX config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + } + return retval; +} + +#define CFG_VGA 0 +#define CFG_ILI 1 +#define CFG_ST 2 + +static int emu_readGfxConfig(void) +{ + int retval = CFG_VGA; // No file = VGA + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + if (filesize == 2) // "ST" + { + retval = CFG_ST; + } + else if (filesize == 3) // "ILI" + { + retval = CFG_ILI; + } + lofile.close(); + } + return retval; +} + /******************************** * File IO compatibility ********************************/ @@ -1670,62 +1794,249 @@ FRESULT f_mkdir (const char* path) /******************************** - * Initialization + * GFX wrapper ********************************/ -void emu_init(void) +static unsigned short palette16[PALETTE_SIZE]; +static IntervalTimer myTimer; +volatile boolean vbl=true; +volatile boolean vgatimervsync=false; +static void (*vblCallback)(void) = nullptr; +static int skip=0; + +static void vblCount() { + if (vbl) { + vbl = false; + } else { + vbl = true; + } +} + +void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) +{ + if (index= MODE_VGA_320x240 ) { + if (vgatimervsync) { + while (vbl==vb) {}; + } + else { + tft.waitSync(); + } + } + else { + while (vbl==vb) {}; + } + if (vblCallback != nullptr) { + vblCallback(); + } +} + +void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride) +{ + if (skip == 0) { + tft.writeScreenPal(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); + } +} +void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLinePal(width,height,line, VBuf, palette16); + } +} + +void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine(width,height,line, VBuf); + } +} + +void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine8(width,height,line, VBuf, palette16); + } +} + +int emu_IsVga(void) +{ + return (tft.getMode() >= MODE_VGA_320x240?1:0); +} + +int emu_IsVgaHires(void) +{ + return (tft.getMode() >= MODE_VGA_640x240?1:0); +} + +int emu_FrameSkip(void) +{ + return skip; +} + + +/******************************** + * AUDIO wrapper +********************************/ +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +AudioPlaySystem mymixer; + +void emu_sndInit() { + Serial.println("sound init"); + mymixer.begin_audio(256, mymixer.snd_Mixer); + mymixer.start(); +} + +void emu_sndPlaySound(int chan, int volume, int freq) +{ + if (chan < 6) { + mymixer.sound(chan, freq, volume); + } + /* + Serial.print(chan); + Serial.print(":" ); + Serial.print(volume); + Serial.print(":" ); + Serial.println(freq); + */ +} + +void emu_sndPlayBuzz(int size, int val) { + mymixer.buzz(size,val); + //Serial.print((val==1)?1:0); + //Serial.print(":"); + //Serial.println(size); +} +#endif + +/******************************** + * Initialization +********************************/ +void emu_init(int hires) { Serial.begin(115200); + vgahires = hires; -#ifdef HAS_USBKEY +#ifdef HAS_USB myusb.begin(); +#ifdef HAS_USBKEY keyboard1.attachPress(OnPress); keyboard1.attachRelease(OnRelease); #endif +#endif - while (!SD.begin(SD_CS)) +#ifdef FILEBROWSER + if (!SD.begin(SD_CS)) { - Serial.println("SD begin failed, retrying..."); - delay(1000); + Serial.println("No SD card detected"); } strcpy(selection,ROMSDIR); - FileHandlersInit(); - nbFiles = readNbFiles(); - - Serial.print("SD initialized, files found: "); Serial.println(nbFiles); +#endif emu_InitJoysticks(); #ifdef SWAP_JOYSTICK - joySwapped = true; + joySwapped = true; #else - joySwapped = false; + joySwapped = false; #endif -#ifdef TEECOMPUTER -#ifndef HAS_T4_VGA - tft.flipscreen(false); -#endif -#endif int keypressed = emu_ReadKeys(); +#ifdef HAS_T4_VGA + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } +#else + int gfx_mode = CFG_VGA; // default +#ifdef FILEBROWSER + gfx_mode = emu_readGfxConfig(); +#endif + // Force VGA if UP pressed + if (keypressed & MASK_JOY2_UP) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("VGA"); +#endif + gfx_mode = CFG_VGA; + } + else { + if (keypressed & MASK_JOY2_LEFT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ST"); +#endif + gfx_mode = CFG_ST; + } + else if (keypressed & MASK_JOY2_RIGHT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ILI"); +#endif + gfx_mode = CFG_ILI; + } + } + if (gfx_mode == CFG_VGA) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + else + { + tft.begin(gfx_mode == CFG_ILI?MODE_TFTILI_320x240:MODE_TFTST_320x240); + } +#endif + if (keypressed & MASK_JOY2_DOWN) { tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) ); tft.drawTextNoDma(64,48, (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); +#ifdef FILEBROWSER emu_eraseConfig(); delay(1000); +#endif } else { +#ifdef FILEBROWSER if (emu_readConfig()) { autorun = true; } +#endif } +#ifdef FILEBROWSER toggleMenu(true); +#endif } -void emu_start(void) +void emu_start(int vblms, void * callback, int forcetimervsync) { + vgatimervsync = forcetimervsync?true:false; + tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); + tft.startRefresh(); + if (callback != nullptr) { + vblCallback = callback; + } + + myTimer.begin(vblCount, vblms); +#ifdef HAS_SND + emu_sndInit(); +#endif usbnavpad = 0; } diff --git a/MCUME_teensy41/teecomputerkeytest/emuapi.h b/MCUME_teensy41/teecomputerkeytest/emuapi.h index 450f428..5dd6130 100644 --- a/MCUME_teensy41/teecomputerkeytest/emuapi.h +++ b/MCUME_teensy41/teecomputerkeytest/emuapi.h @@ -2,127 +2,14 @@ #define EMUAPI_H #include "platform_config.h" - -#define CUSTOM_SND 1 -//#define TIMER_REND 1 - -#define EXTRA_HEAP 0x10 - -// Title: < > -#define TITLE " Emulator " -#define ROMSDIR "/c64" - -#define emu_Init(ROM1,ROM2) {uae_Start(ROM1,ROM2);} -#define emu_Init2() {uae_Init();} -#define emu_Step(x) {uae_Step();} -#define emu_Input(x) {uae_Input(x);} - -#define MAX_FILENAME_PATH 64 -#define NB_FILE_HANDLER 4 -#define PALETTE_SIZE 1 -#define VID_FRAME_SKIP 0x0 -#define TFT_VBUFFER_YCROP 0 -#define SINGLELINE_RENDERING 1 - -#define R32(rgb) ((rgb>>16)&0xff) -#define G32(rgb) ((rgb>>8)&0xff) -#define B32(rgb) (rgb & 0xff) +#include "emucfg.h" #define ACTION_NONE 0 -#define ACTION_MAXKBDVAL 16 -#define ACTION_EXITKBD 128 -#define ACTION_RUN1 129 -#define ACTION_RUN2 130 -#define ACTION_RUN3 131 - - -#ifdef KEYMAP_PRESENT - -#define keylables_map0_0 (char *)"qwertyuiop\x1a" -#define keylables_map0_1 (char *)" asdfghjkl\x19" -#define keylables_map0_2 (char *)" zxcvbnm,.;/" -#define keylables_map0_3 (char *)" +\x10-" -const unsigned short key_map0[] = { - 'q','w','e','r','t','y','u','i','o','p',157, //lowecase - 0,'a','s','d','f','g','h','j','k','l',0x0D, - 0,'z','x','c','v','b','n','m',',','.',';','/', - 145,157,29,17, - 0,'+',' ','-' - }; - -#define keylables_map1_0 (char *)"QWERTYUIOP@" -#define keylables_map1_1 (char *)" ASDFGHJKL\x19" -#define keylables_map1_2 (char *)" ZXCVBNM<>:?" -#define keylables_map1_3 (char *)" =\x10_" -const unsigned short key_map1[] = { - 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase - 0,'A','S','D','F','G','H','J','K','L',0x0D, - 0,'Z','X','C','V','B','N','M','<','>',':','?', - 145,157,29,17, - 0,'=',' ','_' - }; - -#define keylables_map2_0 (char *)"!\"#$%^&*()@" -#define keylables_map2_1 (char *)" |\\[]{}' " -#define keylables_map2_2 (char *)" <>:?" -#define keylables_map2_3 (char *)" =\x10_" -const unsigned short key_map2[] = { - '!','"','#','$','%','^','&','*','(',')','@', // shiftothers - 0, '|','\\','[',']','{','}','\'',0,0,0, - 0, 0,0,0,0,0,0,0,'<','>',':','?', - 0,0,0,0, - 0,'=',' ','_' - }; - -#define keylables_map3_0 (char *)"1234567890 " -#define keylables_map3_1 (char *)" " -#define keylables_map3_2 (char *)" " -#define keylables_map3_3 (char *)" " - -const unsigned short key_map3[] = { - '1','2','3','4','5','6','7','8','9','0',0, // digit keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map4_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " -#define keylables_map4_1 (char *)" " -#define keylables_map4_2 (char *)" " -#define keylables_map4_3 (char *)" " - -const unsigned short key_map4[] = { - 133,134,135,136,137,138,139,140,0,0,0, // function keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map5_0 (char *)" " -#define keylables_map5_1 (char *)" " -#define keylables_map5_2 (char *)" " -#define keylables_map5_3 (char *)" " - -const unsigned short key_map5[] = { - 0,0,0,0,0,0,0,0,0,0,0, // extra keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -const unsigned short matkeys[] = { - 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 - 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 - 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 - 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN - 0x510,0x010,0x110,0x310, // row 4 - }; - -#endif +#define ACTION_RUN1 1 +#define ACTION_RUN2 2 +#define FORCE_VGATIMERVSYNC 1 +#define SUPPORT_HIRES 1 #define MASK_JOY2_RIGHT 0x0001 #define MASK_JOY2_LEFT 0x0002 @@ -139,21 +26,25 @@ const unsigned short matkeys[] = { #define MASK_JOY1_BTN 0x1000 #define MASK_KEY_USER4 0x2000 +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) + #ifdef __cplusplus extern "C" { +extern void emu_init(int hires=0); +extern void emu_start(int vblms, void * callback, int forcetimervsync=0); #endif - -extern void emu_init(void); -extern void emu_start(void); extern void emu_printf(const char * text); extern void emu_printi(int val); extern void emu_printh(int val); extern void * emu_Malloc(unsigned int size); extern void * emu_MallocI(unsigned int size); extern void emu_Free(void * pt); +extern void * emu_SMalloc(unsigned int size); +extern void emu_SFree(void * pt); extern int emu_FileOpen(const char * filepath, const char * mode); extern int emu_FileRead(void * buf, int size, int handler); +extern int emu_FileWrite(void * buf, int size, int handler); extern int emu_FileGetc(int handler); extern int emu_FileSeek(int handler, int seek, int origin); extern int emu_FileTell(int handler); @@ -164,24 +55,23 @@ extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size); extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek); extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index); -extern void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride); -extern void emu_DrawLine(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line); extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line); +extern void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride); extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line); -extern void emu_CopyLine(int width, int height, int ysrc, int ydst); extern void emu_DrawVsync(void); extern int emu_FrameSkip(void); -extern void * emu_LineBuffer(int line); -extern void emu_tweakVideo(int shiftdelta, int numdelta, int denomdelta); +extern int emu_IsVga(void); +extern int emu_IsVgaHires(void); -extern bool menuActive(void); +extern int menuActive(void); extern char * menuSelection(void); extern char * menuSecondSelection(void); -extern void toggleMenu(bool on); +extern void toggleMenu(int on); extern int handleMenu(unsigned short bClick); extern int handleOSKB(void); -extern void toggleOSKB(bool forceon); +extern void toggleOSKB(int forceon); extern void emu_InitJoysticks(void); extern int emu_SwapJoysticks(int statusOnly); @@ -190,6 +80,7 @@ extern int emu_ReadKeys(void); extern int emu_GetPad(void); extern int emu_GetMouse(int *x, int *y, int *buts); extern int emu_MouseDetected(void); +extern int emu_GetJoystick(void); extern int emu_KeyboardDetected(void); extern int emu_ReadAnalogJoyX(int min, int max); extern int emu_ReadAnalogJoyY(int min, int max); diff --git a/MCUME_teensy41/teecomputerkeytest/emucfg.h b/MCUME_teensy41/teecomputerkeytest/emucfg.h new file mode 100644 index 0000000..0c6f5d6 --- /dev/null +++ b/MCUME_teensy41/teecomputerkeytest/emucfg.h @@ -0,0 +1,108 @@ +#ifndef EMUCFG_H +#define EMUCFG_H + +// Title: < > +#define TITLE " XXXX Emulator " +#define ROMSDIR "snes" + +#define MAX_FILENAME_PATH 64 +#define NB_FILE_HANDLER 4 +#define PALETTE_SIZE 256 +#define VID_FRAME_SKIP 0x0 +#define TFT_VBUFFER_YCROP 0 +#define SINGLELINE_RENDERING 1 +//#define CUSTOM_SND 1 +//#define TIMER_REND 1 +//#define EXTPAD 1 +#define EXTRA_HEAP 0x10 +#define FILEBROWSER 1 + + +#ifdef KEYMAP_PRESENT + +#define keylables_map0_0 (char *)"QWERTYUIOP\x1a" +#define keylables_map0_1 (char *)" ASDFGHJKL\x19" +#define keylables_map0_2 (char *)" ZXCVBNM,.;/" +#define keylables_map0_3 (char *)" +\x10-" +const unsigned short key_map0[] = { + 'Q','W','E','R','T','Y','U','I','O','P',157, //default C64 uppercase always + 0,'A','S','D','F','G','H','J','K','L',10, + 0,'Z','X','C','V','B','N','M',',','.',';','/', + 0,0,0,0, + 0,'+',' ','-' + }; + +#define keylables_map1_0 (char *)"1234567890 " +#define keylables_map1_1 (char *)" " +#define keylables_map1_2 (char *)" " +#define keylables_map1_3 (char *)" " + +const unsigned short key_map1[] = { + '1','2','3','4','5','6','7','8','9','0',0, // digit keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map2_0 (char *)"!\"#$%^&*()@" +#define keylables_map2_1 (char *)" " +#define keylables_map2_2 (char *)" <>:?" +#define keylables_map2_3 (char *)" =\x10_" +const unsigned short key_map2[] = { + '!','"','#','$','%','^','&','*','(',')','@', // shiftothers + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 153,151,150,152, //U L R D + 0,'=',' ','_' + }; + +#define keylables_map3_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " +#define keylables_map3_1 (char *)" " +#define keylables_map3_2 (char *)" " +#define keylables_map3_3 (char *)" " + +const unsigned short key_map3[] = { + 129,130,131,132,133,134,135,136,0,0,0, // function keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map4_0 (char *)"QWERTYUIOP@" +#define keylables_map4_1 (char *)" ASDFGHJKL\x19" +#define keylables_map4_2 (char *)" ZXCVBNM<>:?" +#define keylables_map4_3 (char *)" =\x10_" +const unsigned short key_map4[] = { + 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase + 0,'A','S','D','F','G','H','J','K','L',10, + 0,'Z','X','C','V','B','N','M','<','>',':','?', + 0,0,0,0, + 0,'=',' ','_' + }; + +#define keylables_map5_0 (char *)" " +#define keylables_map5_1 (char *)" " +#define keylables_map5_2 (char *)" " +#define keylables_map5_3 (char *)" " + +const unsigned short key_map5[] = { + 0,0,0,0,0,0,0,0,0,0,0, // extra keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 153,151,150,152, //U L R D + 0,0,' ',0 + }; + +const unsigned short matkeys[] = { + 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 + 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 + 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 + 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN + 0x510,0x010,0x110,0x310, // row 4 + }; + +#endif + +#endif diff --git a/MCUME_teensy41/teecomputerkeytest/platform_config.h b/MCUME_teensy41/teecomputerkeytest/platform_config.h index c2c67bb..8d0ab10 100644 --- a/MCUME_teensy41/teecomputerkeytest/platform_config.h +++ b/MCUME_teensy41/teecomputerkeytest/platform_config.h @@ -4,27 +4,32 @@ #define TEECOMPUTER 1 #ifdef TEECOMPUTER - -//#define ILI9341 1 -//#define ST7789 1 -//#define TFTSPI1 1 -#define HAS_T4_VGA 1 -//#define HIRES 1 -//#define HAS_SND 1 +#define TFTSPI1 1 +//#define HAS_T4_VGA 1 +#define HAS_SND 1 +#define HAS_USB 1 //#define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 +//#define HAS_USBJOY 1 // not working yet +#define PT8211 1 #else #define HAS_T4_VGA 1 -#define HIRES 1 //#define INVX 1 #define INVY 1 -//#define HAS_SND 1 +#define HAS_SND 1 +#define HAS_USB 1 //#define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 +//#define HAS_USBJOY 1 // not working yet #endif +//#define FLIP_SCREEN 1 //#define ILI9341 1 //#define ST7789 1 //#define SWAP_JOYSTICK 1 diff --git a/MCUME_teensy41/teecomputerkeytest/t4_dsp.cpp b/MCUME_teensy41/teecomputerkeytest/t4_dsp.cpp new file mode 100644 index 0000000..43301fa --- /dev/null +++ b/MCUME_teensy41/teecomputerkeytest/t4_dsp.cpp @@ -0,0 +1,1774 @@ +/* + TFT/VGA driver + DMA TFT driver based on C64 ILI9341 dma driver from Frank Bösing, 2017 +*/ + +#include "T4_DSP.h" + +#include +#include + +#include "font8x8.h" + +// TFT constants and variables +#define TFT_LINEARINT 1 +#define LINEARINT_HACK 1 +#define DMA_LINES_PER_BLOCK 64 +#define DMA_NUM_SETTINGS 4 + +#define TFT_SWRESET 0x01 +#define TFT_SLPOUT 0x11 +#define TFT_INVON 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_MADCTL 0x36 +#define TFT_PIXFMT 0x3A +#define TFT_MADCTL_MY 0x80 +#define TFT_MADCTL_MX 0x40 +#define TFT_MADCTL_MV 0x20 +#define TFT_MADCTL_ML 0x10 +#define TFT_MADCTL_RGB 0x00 +#define TFT_MADCTL_BGR 0x08 +#define TFT_MADCTL_MH 0x04 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) +//#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) +//#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) +//#define R16(rgb) ((rgb>>8)&0xf8) +//#define G16(rgb) ((rgb>>3)&0xfc) +//#define B16(rgb) ((rgb<<3)&0xf8) + +// LPSPI4 = SPI0 in Teensy 4.0 +// LPSPI3 = SPI1 in Teensy 4.0 +// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) + +#ifdef TFTSPI1 +#define SPI SPI1 +#define LPSPIP_TDR LPSPI3_TDR +#define LPSPIP_CR LPSPI3_CR +#define LPSPIP_CFGR1 LPSPI3_CFGR1 +#define LPSPIP_TCR LPSPI3_TCR +#define LPSPIP_DER LPSPI3_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX +#else +#define LPSPIP_TDR LPSPI4_TDR +#define LPSPIP_CR LPSPI4_CR +#define LPSPIP_CFGR1 LPSPI4_CFGR1 +#define LPSPIP_TCR LPSPI4_TCR +#define LPSPIP_DER LPSPI4_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX +#endif + +#define SPICLOCK 60000000 +#define SPI_MODE SPI_MODE0 + +// VGA constants and macros +typedef uint8_t vga_pixel; +#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) + +static DMASetting dmasettings[DMA_NUM_SETTINGS]; +static DMAChannel dmatx; +static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K +static volatile uint8_t rstop = 0; +static volatile bool cancelled = false; +static volatile uint8_t curTransfer = 0; +static uint8_t nbTransfer = 0; +static uint16_t * tft_buffer; +static int tft_width; +static int tft_height; +static int tft_stride; + +#define DELAY_MASK 0x80 +PROGMEM static const uint8_t init_commands[] = { + 1+DELAY_MASK, TFT_SWRESET, 150, + 1+DELAY_MASK, TFT_SLPOUT, 255, + 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, + 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, + 1, TFT_INVON, + 1, TFT_DISPON, + 0 +}; + +// VGA constants and variables +// Objective: +// generates VGA signal fully in hardware with as little as possible CPU help + +// Principle: +// QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) +// 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate +// RGB out, combined to create 8bits(/12bits) output. + +// Note: +// - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels +// - experimental resolution: 352x240,352x480 +// - experimental resolution: 512x240,512x480 (not stable) +// - video memory is allocated using malloc in T4 heap +// - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing +// but tried to be compensated by pixel shifting +// - Default is 8bits RRRGGGBB (332) +// But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! +// - Only ok at 600MHz else some disturbances visible + + + +#define TOP_BORDER 40 +#define PIN_HBLANK 15 + +#define PIN_R_B2 33 +#define PIN_R_B1 4 +#define PIN_R_B0 3 +#define PIN_G_B2 2 +#define PIN_G_B1 13 +#define PIN_G_B0 11 +#define PIN_B_B1 12 +#define PIN_B_B0 10 + + +#define DMA_HACK 0x80 + +#define R16(rgb) ((rgb>>8)&0xf8) +#define G16(rgb) ((rgb>>3)&0xfc) +#define B16(rgb) ((rgb<<3)&0xf8) + +// VGA 640x480@60Hz +// Screen refresh rate 60 Hz +// Vertical refresh 31.46875 kHz +// Pixel freq. 25.175 MHz +// +// Visible area 640 25.422045680238 us +// Front porch 16 0.63555114200596 us +// Sync pulse 96 3.8133068520357 us +// Back porch 48 1.9066534260179 us +// Whole line 800 31.777557100298 us + +#define frame_freq 60.0 // Hz +#define line_freq 31.46875 // KHz +#define pix_freq (line_freq*800) // KHz (25.175 MHz) + +// pix_period = 39.7ns +// H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) +#define frontporch_pix 20 //16 +#define backporch_pix 44 //48 + +// Flexio Clock +// PLL3 SW CLOCK (3) => 480 MHz +// PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) +#define FLEXIO_CLK_SEL_PLL3 3 +#define FLEXIO_CLK_SEL_PLL5 2 + +/* Set video PLL */ +// There are /1, /2, /4, /8, /16 post dividers for the Video PLL. +// The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, +// and CCM_ANALOG_MISC2 register sets according to the following equation. +// PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + +// nfact: +// This field controls the PLL loop divider. +// Valid range for DIV_SELECT divider value: 27~54. + +#define POST_DIV_SELECT 2 + +// Full buffer including back/front porch +static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; +static uint32_t dstbuffer __attribute__((aligned(32))); + +// Visible vuffer +static vga_pixel * vga_buffer; +static int vga_width; +static int vga_height; +static int vga_stride; + +static int maxpixperline; +static int left_border; +static int right_border; +static int line_double; +static int pix_shift; +static int ref_div_select; +static int ref_freq_num; +static int ref_freq_denom; +static int ref_pix_shift; +static int combine_shiftreg; + +#ifdef DEBUG +static uint32_t ISRTicks_prev = 0; +volatile uint32_t ISRTicks = 0; +#endif + +uint8_t T4_DSP::_rst; +uint8_t T4_DSP::_cs; +uint8_t T4_DSP::_dc; +uint8_t T4_DSP::_mosi; +uint8_t T4_DSP::_sclk; +uint8_t T4_DSP::_vsync_pin = -1; +DMAChannel T4_DSP::flexio1DMA; +DMAChannel T4_DSP::flexio2DMA; + +static volatile uint32_t VSYNC = 0; +static volatile uint32_t currentLine=0; +#define NOP asm volatile("nop\n\t"); +static gfx_mode_t gfxmode = MODE_UNDEFINED; + + +FASTRUN void T4_DSP::TFT_isr(void) { + dmatx.clearInterrupt(); + curTransfer++; + if (curTransfer >= nbTransfer) { + curTransfer = 0; + if (cancelled) { + dmatx.disable(); + rstop = 1; + } + } + arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); +} + +FASTRUN void T4_DSP::QT3_isr(void) { + TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); + TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); + + cli(); + + // V-PULSE + if (currentLine > 0) { + digitalWrite(_vsync_pin, 1); + VSYNC = 0; + } else { + digitalWrite(_vsync_pin, 0); + VSYNC = 1; + } + + currentLine++; + currentLine = currentLine % 525; + + + uint32_t y = (currentLine - TOP_BORDER) >> line_double; + // Visible area + + if (y >= 0 && y < vga_height) { + // Disable DMAs + //DMA_CERQ = flexio2DMA.channel; + //DMA_CERQ = flexio1DMA.channel; + + // Setup source adress + // Aligned 32 bits copy + unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; + flexio2DMA.TCD->SADDR = p; + if (pix_shift & DMA_HACK) + { + // Unaligned copy + uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; + flexio1DMA.TCD->SADDR = p2; + } + else { + p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 + flexio1DMA.TCD->SADDR = p; + } + + // Enable DMAs + //flexio2DMA.enable(); + //flexio1DMA.enable(); + DMA_SERQ = flexio2DMA.channel; + DMA_SERQ = flexio1DMA.channel; + arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); + } + sei(); + +#ifdef DEBUG + ISRTicks++; +#endif + asm volatile("dsb"); +} + +static void setDmaStruct() { + uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; + uint16_t * fb = (uint16_t*)malloc(remaining); + tft_buffer = fb; + tft_width = TFT_WIDTH; + tft_height = TFT_HEIGHT; + tft_stride = TFT_WIDTH; + uint16_t col=RGBVAL16(0x00,0x00,0x00); + int i=0; + while (remaining > 0) { + int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); + blocks[i] = fb; + for (int j=0;jATTR_DST = 1; + dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); + dmasettings[i].interruptAtCompletion(); + fb += len/2; + remaining -= len; + i++; + } + dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); + nbTransfer = i; +} + +static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 +{ +//if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; + CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE + | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 + | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); + CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; + CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock + const int div_post_pll = 1; // other values: 2,4 + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass +} + +T4_DSP::T4_DSP() +{ + _cs = TFT_CS; + _dc = TFT_DC; + _rst = TFT_RST; + _mosi = TFT_MOSI; + _sclk = TFT_SCLK; + pinMode(_dc, OUTPUT); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, 1); + digitalWrite(_dc, 1); + _vsync_pin = 8; +} + + +void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { + int dx=0; + int dy=0; + digitalWrite(_dc, 0); + SPI.transfer(TFT_CASET); + digitalWrite(_dc, 1); + SPI.transfer16(x1+dx); + digitalWrite(_dc, 1); + SPI.transfer16(x2+dx); + digitalWrite(_dc, 0); + SPI.transfer(TFT_PASET); + digitalWrite(_dc, 1); + SPI.transfer16(y1+dy); + digitalWrite(_dc, 1); + SPI.transfer16(y2+dy); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + return; +} + +void T4_DSP::tft_setup(bool isST) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + // RESET if reset pin defined + if (_rst != 0xff) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + const uint8_t *addr = init_commands; + uint8_t count; + digitalWrite(_cs, 0); + while (count = *addr++) { + uint8_t command = *addr++; + if ( (command == TFT_INVON) && (!isST) ) { + // Skip TFT_INVON for ILI + } + else { + digitalWrite(_dc, 0); // command + SPI.transfer(command); + uint16_t ms = count & DELAY_MASK; + count &= ~DELAY_MASK; + while (--count > 0) { // data + uint8_t data = *addr++; + if ( (command == TFT_MADCTL) && (isST) ) { + data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; + } + digitalWrite(_dc, 1); + SPI.transfer(data); + } + if (ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + digitalWrite(_cs, 1); + SPI.endTransaction(); + delay(2); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + } + } + } + digitalWrite(_cs, 1); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + SPI.endTransaction(); + /* + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_dc, 0); + digitalWrite(_cs, 0); + SPI.transfer(TFT_MADCTL); + digitalWrite(_dc, 1); + SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); + // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); + digitalWrite(_cs, 1); + SPI.endTransaction(); + */ + cancelled = false; +} + +// display VGA image +gfx_error_t T4_DSP::begin(gfx_mode_t mode) +{ + uint32_t flexio_clock_div; + combine_shiftreg = 0; +// int div_select = 49; +// int num = 135; +// int denom = 100; + int div_select = 20; + int num = 9800; + int denom = 10000; + int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; + int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; + set_videoClock(div_select,num,denom,true); + +#ifdef DEBUG + Serial.println(mode); + Serial.println("mode"); +#endif + + switch(mode) + { + case MODE_TFTILI_320x240: +#ifdef DEBUG + Serial.println("TFTILI_320x240"); +#endif + tft_setup(false); + gfxmode = mode; + break; + case MODE_TFTST_320x240: +#ifdef DEBUG + Serial.println("TFTST_320x240"); +#endif + tft_setup(true); + gfxmode = mode; + break; + + case MODE_VGA_320x240: +#ifdef DEBUG + Serial.println("VGA_320x240"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_320x480: +#ifdef DEBUG + Serial.println("VGA_320x480"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_640x240: +#ifdef DEBUG + Serial.println("VGA_640x240"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/pix_freq; + line_double = 1; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_640x480: +#ifdef DEBUG + Serial.println("VGA_640x480"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = (flexio_freq/pix_freq); + line_double = 0; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_512x240: +#ifdef DEBUG + Serial.println("VGA_512x240"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 1; + pix_shift = 0; + break; + + case MODE_VGA_512x480: +#ifdef DEBUG + Serial.println("VGA_512x480"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 0; + pix_shift = 0; + break; + + case MODE_VGA_352x240: +#ifdef DEBUG + Serial.println("VGA_352x240"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_352x480: +#ifdef DEBUG + Serial.println("VGA_352x480"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + } + + if (mode >= MODE_VGA_320x240) + { + if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { + fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); + digitalWrite(_cs, 0); + digitalWrite(_dc, 0); + SPI.transfer(TFT_DISPOFF); + digitalWrite(_cs, 1); + delay(20); + digitalWrite(_cs, 0); + digitalWrite(_cs, 1); + } + gfxmode = mode; + + maxpixperline = vga_stride; + // Save param for tweek adjustment + ref_div_select = div_select; + ref_freq_num = num; + ref_freq_denom = denom; + ref_pix_shift = pix_shift; + +#ifdef DEBUG + Serial.println("frequency"); + Serial.println(flexio_freq); + Serial.println("div"); + Serial.println(flexio_freq/pix_freq); +#endif + + pinMode(_vsync_pin, OUTPUT); + pinMode(PIN_HBLANK, OUTPUT); + + /* Basic pin setup FlexIO1 */ + pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 + pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 + pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 + pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 + /* Basic pin setup FlexIO2 */ + pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 + pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 + pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 + pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 + + /* High speed and drive strength configuration */ + *(portControlRegister(PIN_G_B2)) = 0xFF; + *(portControlRegister(PIN_R_B0)) = 0xFF; + *(portControlRegister(PIN_R_B1)) = 0xFF; + *(portControlRegister(PIN_R_B2)) = 0xFF; + *(portControlRegister(PIN_B_B0)) = 0xFF; + *(portControlRegister(PIN_B_B1)) = 0xFF; + *(portControlRegister(PIN_G_B0)) = 0xFF; + *(portControlRegister(PIN_G_B1)) = 0xFF; + + /* Set clock for FlexIO1 and FlexIO2 */ + CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) + | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); + CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) + | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); + + + /* Set up pin mux FlexIO1 */ + *(portConfigRegister(PIN_G_B2)) = 0x14; + *(portConfigRegister(PIN_R_B0)) = 0x14; + *(portConfigRegister(PIN_R_B1)) = 0x14; + *(portConfigRegister(PIN_R_B2)) = 0x14; + /* Set up pin mux FlexIO2 */ + *(portConfigRegister(PIN_B_B0)) = 0x14; + *(portConfigRegister(PIN_B_B1)) = 0x14; + *(portConfigRegister(PIN_G_B0)) = 0x14; + *(portConfigRegister(PIN_G_B1)) = 0x14; + + /* Enable the clock */ + CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + /* Enable the FlexIO with fast access */ + FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + + uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; + uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; + + /* Shifter 0 registers for FlexIO2 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 + inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter + stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled + startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable + timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 + timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock + pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output + pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity + shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode + /* Shifter 0 registers for FlexIO1 */ + FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + /* Shifter 0 registers for FlexIO1 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 + FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + if (combine_shiftreg) { + pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled + FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + } + /* Timer 0 registers for FlexIO2 */ + timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset + timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output + timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset + timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare + timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert + stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled + startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled + if (combine_shiftreg) { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag + } + else { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag + } + triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low + triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected + pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled + //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 + //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high + timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode + // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) + + int shifts_per_transfer; + if (combine_shiftreg) { + shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 + } + else { + shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 + } + FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); + /* Timer 0 registers for FlexIO1 */ + FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); +#ifdef DEBUG + Serial.println("FlexIO setup complete"); +#endif + + /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ + if (combine_shiftreg) { + FLEXIO2_SHIFTSDEN |= (1<<1); + FLEXIO1_SHIFTSDEN |= (1<<1); + } + else { + FLEXIO2_SHIFTSDEN |= (1<<0); + FLEXIO1_SHIFTSDEN |= (1<<0); + } + /* Disable DMA channel so it doesn't start transferring yet */ + flexio1DMA.disable(); + flexio2DMA.disable(); + /* Set up DMA channel to use Shifter 0 trigger */ + flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); + flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); + + + if (combine_shiftreg) { + flexio2DMA.TCD->NBYTES = 8; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 8; + flexio2DMA.TCD->CITER = maxpixperline / 8; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + flexio1DMA.TCD->NBYTES = 8; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 8; + flexio1DMA.TCD->CITER = maxpixperline / 8; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Setup DMA2 Flexio2 copy + flexio2DMA.TCD->NBYTES = 4; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 4; + flexio2DMA.TCD->CITER = maxpixperline / 4; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + // Setup DMA1 Flexio1 copy + // Use pixel shift to avoid color smearing? + if (pix_shift & DMA_HACK) + { + if (pix_shift & 0x3 == 0) { + // Aligned 32 bits copy (32bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Unaligned (source) 32 bits copy (8bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 1; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion + } + } + else + { + // Aligned 32 bits copy + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + } + +#ifdef DEBUG + Serial.println("DMA setup complete"); +#endif + + // enable clocks for QTIMER3: generates the 15KHz for hsync + // Pulse: + // low : 3.8133 us => 569x6.7ns + // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) + // (OLD TEST) + // (4us low, 28us high => 32us) + // (597x6.7ns for 4us) + // (4179x6.7ns for 28us) + CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 + //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 + + #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz + #define MARGIN_D 1000 + + TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer + // Invert output pin as we want the interupt on rising edge + TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) + TMR3_CNTR3 = 0; + TMR3_LOAD3 = 0; + + /* Inverted timings */ + unsigned long long cpu_freq = F_CPU; + unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; + int rate2 = rate; + + int substract = 1; + if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { + substract=5; + rate2=1652; + } + + #ifdef DEBUG + Serial.print("MARGIN_N is: "); + Serial.println(rate2, DEC); + Serial.print("SUBSTRACT is: "); + Serial.println(substract, DEC); +#endif + TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; + TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; + /* + TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; + */ + TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on + TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), + // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) + //configure Teensy pin Compare output + IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 + attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function + NVIC_ENABLE_IRQ(IRQ_QTIMER3); +#ifdef DEBUG + Serial.println("QTIMER3 setup complete"); + Serial.print("V-PIN is "); + Serial.println(_vsync_pin); +#endif + + /* initialize gfx buffer */ + if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift + if (gfxbuffer == NULL) return(GFX_ERROR); +#ifdef DEBUG + Serial.println("Memory allocated"); +#endif + + memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); + vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; +#ifdef DEBUG + Serial.println(vga_stride); + Serial.println(vga_height); + Serial.println("Screen cleared"); +#endif + } + + return(GFX_OK); +} + +gfx_mode_t T4_DSP::getMode(void) +{ + return gfxmode; +} + +void T4_DSP::startRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + curTransfer = 0; + rstop = 0; + //dmatx.begin(true); + dmatx.attachInterrupt(TFT_isr); + setDmaStruct(); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + + digitalWrite(_cs, HIGH); + SPI.begin(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + + LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: + LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX + LPSPIP_TCR = 15; // Framesize 16 Bits + //LPSPIP_FCR = 0; // Fifo Watermark + LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable + LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: + dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); + + dmatx = dmasettings[0]; + digitalWrite(_cs, 0); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + dmatx.enable(); + } +} + + +void T4_DSP::stopRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + rstop = 1; + unsigned long m = millis(); + cancelled = true; + while (!rstop) { + if ((millis() - m) > 100) break; + delay(10); + asm volatile("wfi"); + }; + rstop = 0; + delay(50); + cancelled = false; + dmatx.detachInterrupt(); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + SPI.end(); +#ifdef ST7789 +// begin(gfxmode); +#endif + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + } +} + +int T4_DSP::get_frame_buffer_size(int *width, int *height) { + if (gfxmode < MODE_VGA_320x240) { + if (width != nullptr) *width = tft_width; + if (height != nullptr) *height = tft_height; + return tft_stride; + } + else { + if (width != nullptr) *width = vga_width; + if (height != nullptr) *height = vga_height; + return vga_stride; + } +} + +void T4_DSP::waitSync() +{ + if (gfxmode >= MODE_VGA_320x240) { + while (VSYNC == 0) {}; + } +} + +void T4_DSP::waitLine(int line) +{ + if (gfxmode >= MODE_VGA_320x240) { + while (currentLine != line) {}; + } +} + +/*********************************************************************************************** + No DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreenNoDma(uint16_t color) { + if (gfxmode < MODE_VGA_320x240) { + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + int i,j; + for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(arx, ary, arx+arw-1, ary+arh-1); + bitmap = bitmap + bmp_offy*w + bmp_offx; + for (int row=0;row> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + bits = *charpt++; + //digitalWrite(_dc, 1); + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + x +=8; + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + else { + drawText(x, y, text, fgcolor, bgcolor, doublesize); + } +} + + +/*********************************************************************************************** + DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreen(uint16_t color) { + int i,j; + if (gfxmode < MODE_VGA_320x240) { + for (j=0; j> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + dst=&tft_buffer[l*tft_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + x +=8; + } + } + else { + vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); + vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); + vga_pixel * dst; + while ((c = *text++)) { + const unsigned char * charpt=&font8x8[c][0]; + int l=y; + for (int i=0;i<8;i++) + { + unsigned char bits; + if (doublesize) { + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + x +=8; + } + } +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { + drawSprite(x,y,bitmap, 0,0,0,0); +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) +{ + int bmp_offx = 0; + int bmp_offy = 0; + uint16_t *bmp_ptr; + int w =*bitmap++; + int h = *bitmap++; + if ( (arw == 0) || (arh == 0) ) { + // no crop window + arx = x; + ary = y; + arw = w; + arh = h; + } + else { + if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + int l=ary; + bitmap = bitmap + bmp_offy*w + bmp_offx; + + if (gfxmode < MODE_VGA_320x240) { + for (int row=0;row tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]; + pos +=step; + } + #endif + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i 2) ) y += (tft_height-height)/2; + uint16_t * dst=&tft_buffer[y*tft_stride]; + if (width > tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]]; + pos +=step; + } +#endif + } + else if ((width*2) == tft_width) { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]]; + *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i tft_width) { + int step = ((width << 8)/tft_width); + int pos = 0; + for (int i=0; i> 8]]; + pos +=step; + } + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = pix; + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i +#include +#endif + +#include "platform_config.h" +#include "iopins.h" + + + +#ifndef TFT_WIDTH +#define TFT_WIDTH 320 +#endif +#define TFT_REALWIDTH 320 + +#ifndef TFT_HEIGHT +#define TFT_HEIGHT 240 +#endif +#define TFT_REALHEIGHT 240 + + +typedef enum gfx_mode_t +{ + MODE_UNDEFINED = 0, + MODE_TFTILI_320x240 = 1, + MODE_TFTST_320x240 = 2, + MODE_VGA_320x240 = 3, + MODE_VGA_320x480 = 4, + MODE_VGA_352x240 = 5, + MODE_VGA_352x480 = 6, + MODE_VGA_512x240 = 7, + MODE_VGA_512x480 = 8, + MODE_VGA_640x240 = 9, + MODE_VGA_640x480 = 10 +} gfx_mode_t; + +typedef enum gfx_error_t +{ + GFX_OK = 0, + GFX_ERROR = -1 +} gfx_error_t; + + +#ifdef __cplusplus + +class T4_DSP +{ + public: + T4_DSP(); + + gfx_error_t begin(gfx_mode_t mode); + gfx_mode_t getMode(void); + void startRefresh(void); + void stopRefresh(); + + int get_frame_buffer_size(int *width, int *height); + void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); + + // wait next Vsync + void waitSync(); + void waitLine(int line); + + // NoDMA functions + void fillScreenNoDma(uint16_t color); + void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + // DMA functions + void fillScreen(uint16_t color); + void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + void writeLine(int width, int height, int y, uint16_t *buf); + void writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + void writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16); + void writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + + protected: + static uint8_t _rst, _cs, _dc; + static uint8_t _mosi, _sclk; + static uint8_t _vsync_pin; + static DMAChannel flexio1DMA; + static DMAChannel flexio2DMA; + void tft_setup(bool isST); + static void TFT_isr(void); + static void QT3_isr(void); +}; + +#endif +#endif diff --git a/MCUME_teensy41/teecomputerkeytest/teecomputerkeytest.ino b/MCUME_teensy41/teecomputerkeytest/teecomputerkeytest.ino index d52f62a..29efd4c 100644 --- a/MCUME_teensy41/teecomputerkeytest/teecomputerkeytest.ino +++ b/MCUME_teensy41/teecomputerkeytest/teecomputerkeytest.ino @@ -1,217 +1,94 @@ #include "emuapi.h" #include "iopins.h" -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -TFT_T_DMA tft; -#else -#include "tft_t_dma.h" -TFT_T_DMA tft = TFT_T_DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, TFT_TOUCH_CS, TFT_TOUCH_INT); -#endif - -bool vgaMode = false; - -static unsigned char palette8[PALETTE_SIZE]; -static unsigned short palette16[PALETTE_SIZE]; -static IntervalTimer myTimer; -volatile boolean vbl=true; -static int skip=0; -static elapsedMicros tius; - +#include "t4_dsp.h" +extern T4_DSP tft; #define BLUE RGBVAL16(0, 0, 170) #define LIGHT_BLUE RGBVAL16(0, 136, 255) static int fb_width, fb_height; static const char * digits = "0123456789ABCDEF"; -static int hk = 0; static int prevhk = 0; static int col=0; static int row=0; - -static void vblCount() { - if (vbl) { - vbl = false; - } else { - vbl = true; - } - uint16_t bClick = emu_DebounceLocalKeys(); - hk = emu_ReadI2CKeyboard(); - //emu_Input(bClick); -} - -void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) -{ - if (index>12)&0xf]; buf[1] = digits[(bClick>>8)&0xf]; buf[2] = digits[(bClick>>4)&0xf]; buf[3] = digits[bClick&0xf]; - tft.drawTextNoDma(4*8,0,buf,RGBVAL16(0x00,0x00,0x00),RGBVAL16(0xFF,0xFF,0xFF),false); + tft.drawText(4*8,0,buf,RGBVAL16(0x00,0x00,0x00),RGBVAL16(0xFF,0xFF,0xFF),false); buf[3] = 0; int key = emu_ReadI2CKeyboard(); buf[0] = digits[(key>>8)&0xf]; buf[1] = digits[(key>>4)&0xf]; buf[2] = digits[key&0xf]; - tft.drawTextNoDma(4*8,8,buf,RGBVAL16(0x00,0x00,0x00),RGBVAL16(0xFF,0xFF,0xFF),false); - + tft.drawText(4*8,8,buf,RGBVAL16(0x00,0x00,0x00),RGBVAL16(0xFF,0xFF,0xFF),false); buf[2] = 0; key = emu_ReadI2CKeyboard2(0); buf[0] = digits[(key>>4)&0xf]; buf[1] = digits[key&0xf]; - tft.drawTextNoDma(9*8+0*24,0*8,buf,RGBVAL16(0x00,0x00,0x00),RGBVAL16(0xFF,0xFF,0xFF),true); + tft.drawText(9*8+0*24,0*8,buf,RGBVAL16(0x00,0x00,0x00),RGBVAL16(0xFF,0xFF,0xFF),true); key = emu_ReadI2CKeyboard2(1); buf[0] = digits[(key>>4)&0xf]; buf[1] = digits[key&0xf]; - tft.drawTextNoDma(9*8+1*24,0*8,buf,RGBVAL16(0x00,0x00,0x00),RGBVAL16(0xFF,0xFF,0xFF),true); + tft.drawText(9*8+1*24,0*8,buf,RGBVAL16(0x00,0x00,0x00),RGBVAL16(0xFF,0xFF,0xFF),true); key = emu_ReadI2CKeyboard2(2); buf[0] = digits[(key>>4)&0xf]; buf[1] = digits[key&0xf]; - tft.drawTextNoDma(9*8+2*24,0*8,buf,RGBVAL16(0x00,0x00,0x00),RGBVAL16(0xFF,0xFF,0xFF),true); + tft.drawText(9*8+2*24,0*8,buf,RGBVAL16(0x00,0x00,0x00),RGBVAL16(0xFF,0xFF,0xFF),true); key = emu_ReadI2CKeyboard2(3); buf[0] = digits[(key>>4)&0xf]; buf[1] = digits[key&0xf]; - tft.drawTextNoDma(9*8+3*24,0*8,buf,RGBVAL16(0x00,0x00,0x00),RGBVAL16(0xFF,0xFF,0xFF),true); + tft.drawText(9*8+3*24,0*8,buf,RGBVAL16(0x00,0x00,0x00),RGBVAL16(0xFF,0xFF,0xFF),true); key = emu_ReadI2CKeyboard2(4); buf[0] = digits[(key>>4)&0xf]; buf[1] = digits[key&0xf]; - tft.drawTextNoDma(9*8+4*24,0*8,buf,RGBVAL16(0x00,0x00,0x00),RGBVAL16(0xFF,0xFF,0xFF),true); + tft.drawText(9*8+4*24,0*8,buf,RGBVAL16(0x00,0x00,0x00),RGBVAL16(0xFF,0xFF,0xFF),true); key = emu_ReadI2CKeyboard2(5); buf[0] = digits[(key>>4)&0xf]; buf[1] = digits[key&0xf]; - tft.drawTextNoDma(9*8+5*24,0*8,buf,RGBVAL16(0x00,0x00,0x00),RGBVAL16(0xFF,0xFF,0xFF),true); -*/ - handleOSKB(); + tft.drawText(9*8+5*24,0*8,buf,RGBVAL16(0x00,0x00,0x00),RGBVAL16(0xFF,0xFF,0xFF),true); + + bClick = emu_DebounceLocalKeys(); + int hk = hk = emu_ReadI2CKeyboard(); + //handleOSKB(); if ( (hk != 0) && (hk < 128) ) { buf[0] = (char)(hk&0xff); buf[1] = 0; - tft.drawTextNoDma(col*8,(row+3)*8,buf,LIGHT_BLUE,BLUE,false); + tft.drawText(col*8,(row+3)*8,buf,LIGHT_BLUE,BLUE,false); col += 1; if (col >= 40) { col=0; @@ -231,67 +108,3 @@ void loop(void) delay(20); } - -// **************************************************** -// the loop() method runs continuously -// **************************************************** -void loop2(void) -{ - if (menuActive()) { - uint16_t bClick = emu_DebounceLocalKeys(); - int action = handleMenu(bClick); - char * floppy1 = menuSelection(); - if (action == ACTION_RUN1) { - toggleMenu(false); - vgaMode = false; - tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); - tft.startDMA(); - } - - delay(20); - } - else { - uint16_t bClick = 0; //emu_DebounceLocalKeys(); - } -} - -#ifdef HAS_SND - -#include "AudioPlaySystem.h" - -AudioPlaySystem mymixer; - - -void emu_sndInit() { - Serial.println("sound init"); -#ifdef HAS_T4_VGA - tft.begin_audio(256, mymixer.snd_Mixer); -#else - mymixer.begin_audio(256, mymixer.snd_Mixer); -#endif - // sgtl5000_1.enable(); - // sgtl5000_1.volume(0.6); - mymixer.start(); -} - -void emu_sndPlaySound(int chan, int volume, int freq) -{ - if (chan < 6) { - mymixer.sound(chan, freq, volume); - } - /* - Serial.print(chan); - Serial.print(":" ); - Serial.print(volume); - Serial.print(":" ); - Serial.println(freq); - */ -} - -void emu_sndPlayBuzz(int size, int val) { - mymixer.buzz(size,val); - //Serial.print((val==1)?1:0); - //Serial.print(":"); - //Serial.println(size); -} -#endif diff --git a/MCUME_teensy41/teecomputerkeytest/tft_t_dma.cpp b/MCUME_teensy41/teecomputerkeytest/tft_t_dma.cpp deleted file mode 100644 index 176962e..0000000 --- a/MCUME_teensy41/teecomputerkeytest/tft_t_dma.cpp +++ /dev/null @@ -1,1243 +0,0 @@ -/* - Based on C64 ILI9341 dma driver from Frank Bösing, 2017 -*/ - -#include "TFT_T_DMA.h" - -#ifndef HAS_T4_VGA - -#include "font8x8.h" - -// LPSPI4 = SPI0 in Teensy 4.0 -// LPSPI3 = SPI1 in Teensy 4.0 -// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) -#ifdef TFTSPI1 -#define SPI SPI1 -#define LPSPIP_TDR LPSPI3_TDR -#define LPSPIP_CR LPSPI3_CR -#define LPSPIP_CFGR1 LPSPI3_CFGR1 -#define LPSPIP_TCR LPSPI3_TCR -#define LPSPIP_DER LPSPI3_DER -#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX -#else -#define LPSPIP_TDR LPSPI4_TDR -#define LPSPIP_CR LPSPI4_CR -#define LPSPIP_CFGR1 LPSPI4_CFGR1 -#define LPSPIP_TCR LPSPI4_TCR -#define LPSPIP_DER LPSPI4_DER -#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX -#endif - - -#define SPICLOCK 60000000 //144e6 //Just a number..max speed -#ifdef ILI9341 -#define SPI_MODE SPI_MODE0 -#endif -#ifdef ST7789 -#define SPI_MODE SPI_MODE2 -#endif - -// touch -#define SPI_SETTING SPISettings(2500000, MSBFIRST, SPI_MODE) -#define XPT2046_CFG_START _BV(7) -#define XPT2046_CFG_MUX(v) ((v&0b111) << (4)) -#define XPT2046_CFG_8BIT _BV(3) -#define XPT2046_CFG_12BIT (0) -#define XPT2046_CFG_SER _BV(2) -#define XPT2046_CFG_DFR (0) -#define XPT2046_CFG_PWR(v) ((v&0b11)) -#define XPT2046_MUX_Y 0b101 -#define XPT2046_MUX_X 0b001 -#define XPT2046_MUX_Z1 0b011 -#define XPT2046_MUX_Z2 0b100 - - -#ifdef TFT_STATICFB -static uint16_t fb0[LINES_PER_BLOCK*TFT_WIDTH]; -static uint16_t fb1[LINES_PER_BLOCK*TFT_WIDTH]; -static uint16_t fb2[LINES_PER_BLOCK*TFT_WIDTH]; -static uint16_t fb3[(TFT_HEIGHT-3*LINES_PER_BLOCK)*TFT_WIDTH]; -static uint16_t * blocks[NR_OF_BLOCK]={fb0,fb1,fb2,fb3}; -#else -static uint16_t * blocks[NR_OF_BLOCK]; -#endif - - -static DMASetting dmasettings[SCREEN_DMA_NUM_SETTINGS]; -static DMAChannel dmatx;//(false); -static volatile uint8_t rstop = 0; -static volatile bool cancelled = false; -static volatile uint8_t curTransfer = 0; -static uint8_t nbTransfer = 0; - - -PROGMEM static const uint8_t init_commands[] = { -#ifdef ILI9341 - 4, 0xEF, 0x03, 0x80, 0x02, - 4, 0xCF, 0x00, 0XC1, 0X30, - 5, 0xED, 0x64, 0x03, 0X12, 0X81, - 4, 0xE8, 0x85, 0x00, 0x78, - 6, 0xCB, 0x39, 0x2C, 0x00, 0x34, 0x02, - 2, 0xF7, 0x20, - 3, 0xEA, 0x00, 0x00, - 2, ILI9341_PWCTR1, 0x23, // Power control - 2, ILI9341_PWCTR2, 0x10, // Power control - 3, ILI9341_VMCTR1, 0x3e, 0x28, // VCM control - 2, ILI9341_VMCTR2, 0x86, // VCM control2 - 2, ILI9341_MADCTL, 0x48, // Memory Access Control - 2, ILI9341_PIXFMT, 0x55, - 3, ILI9341_FRMCTR1, 0x00, 0x18, - 4, ILI9341_DFUNCTR, 0x08, 0x82, 0x27, // Display Function Control - 2, 0xF2, 0x00, // Gamma Function Disable - 2, ILI9341_GAMMASET, 0x01, // Gamma curve selected - 16, ILI9341_GMCTRP1, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, - 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, // Set Gamma - 16, ILI9341_GMCTRN1, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, - 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, // Set Gamma -// 3, 0xb1, 0x00, 0x1f, // FrameRate Control 61Hz - 3, 0xb1, 0x00, 0x10, // FrameRate Control 119Hz - 2, ILI9341_MADCTL, ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR, - 0 -#endif -#ifdef ST7789 -#define DELAY 0x80 - 9, // 9 commands in list: - ST7735_SWRESET, DELAY, // 1: Software reset, no args, w/delay - 150, // 150 ms delay - ST7735_SLPOUT , DELAY, // 2: Out of sleep mode, no args, w/delay - 255, // 255 = 500 ms delay - ST7735_COLMOD , 1+DELAY, // 3: Set color mode, 1 arg + delay: - 0x55, // 16-bit color - 10, // 10 ms delay - ST7735_MADCTL , 1 , // 4: Memory access ctrl (directions), 1 arg: - 0x08, // Row addr/col addr, bottom to top refresh - ST7735_CASET , 4 , // 5: Column addr set, 4 args, no delay: - 0x00, - 0x00, // XSTART = 0 - 0x00, - 240, // XEND = 240 - ST7735_RASET , 4 , // 6: Row addr set, 4 args, no delay: - 0x00, - 0x00, // YSTART = 0 - 320>>8, - 320 & 0xFF, // YEND = 320 - ST7735_INVON , DELAY, // 7: hack - 10, - ST7735_NORON , DELAY, // 8: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 9: Main screen turn on, no args, w/delay - 255 -#endif -}; - -static void dmaInterrupt() { - dmatx.clearInterrupt(); - curTransfer++; - if (curTransfer >= nbTransfer) { - curTransfer = 0; - if (cancelled) { - dmatx.disable(); - rstop = 1; - } - } - arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2); -} - -static void setDmaStruct() { - uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; - int i=0; - uint16_t col=RGBVAL16(0x00,0x00,0x00);; - while (remaining > 0) { - uint16_t * fb = blocks[i]; - int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining); -#ifdef TFT_DEBUG - Serial.println((unsigned long)blocks[i]); - Serial.println(remaining); -#endif - switch (i) { - case 0: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb0[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0x00); -#endif - break; - case 1: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb1[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0xff); -#endif - break; - case 2: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb2[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0x00,0xff); -#endif - break; - case 3: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb3[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0xff,0x00,0xff); -#endif - break; - } - blocks[i] = fb; - if (blocks[i] == 0) { - Serial.print("ILI9341 allocaltion failed for block "); - Serial.println(i); - delay(10000); - } - - for (int j=0;jATTR_DST = 1; - dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); - dmasettings[i].interruptAtCompletion(); - remaining -= len; - i++; - } - dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); - nbTransfer = i; -#ifdef TFT_DEBUG - Serial.println(nbTransfer); -#endif -} - - -TFT_T_DMA::TFT_T_DMA(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso, uint8_t touch_cs, uint8_t touch_irq) -{ - _cs = cs; - _dc = dc; - _rst = rst; - _mosi = mosi; - _sclk = sclk; - _miso = miso; - pinMode(_dc, OUTPUT); - pinMode(_cs, OUTPUT); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); - if ( (touch_cs != 255) && (touch_irq != 255) ) { - _touch_irq = touch_irq; - _touch_cs = touch_cs; - pinMode(_touch_cs, OUTPUT); - pinMode(touch_irq, INPUT_PULLUP); - digitalWrite(_touch_cs, 1); - } -} - - -void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { - int dx=0; - int dy=0; -#ifdef ST7789 - if (TFT_REALWIDTH == TFT_REALHEIGHT) - { -#ifdef ROTATE_SCREEN - if (!flipped) { - dy += 80; - } -#else - if (flipped) { - dx += 80; - } -#endif - } -#endif - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - SPI.transfer16(x1+dx); - digitalWrite(_dc, 1); - SPI.transfer16(x2+dx); - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - digitalWrite(_dc, 1); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - return; - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - - SPI.transfer16(x1+dx); - SPI.transfer16(x2+dx); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - -void TFT_T_DMA::begin(void) { - SPI.setMOSI(_mosi); - SPI.setMISO(_miso); - SPI.setSCK(_sclk); - SPI.begin(); - - // Initialize display - if (_rst != 0xff) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - const uint8_t *addr = init_commands; - digitalWrite(_cs, 0); -#ifdef ILI9341 - while (1) { - uint8_t count = *addr++; - if (count-- == 0) break; - - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - - while (count-- > 0) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - } - - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(ILI9341_DISPON); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); -#endif -#ifdef ST7789 - uint8_t numCommands, numArgs; - uint16_t ms; - numCommands = *addr++; // Number of commands to follow - while(numCommands--) { // For each command... - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - numArgs = *addr++; // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs > 1) { // For each argument... - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - numArgs--; - } - - if (numArgs) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - if(ms) { - ms = *addr++; // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - digitalWrite(_cs, 1); - SPI.endTransaction(); - delay(ms); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - } - } - digitalWrite(_cs, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - SPI.endTransaction(); - - cancelled = false; - -#ifdef FLIP_SCREEN - flipscreen(true); -#else - flipscreen(false); -#endif -#ifdef ST7789 - if (TFT_REALWIDTH != TFT_REALHEIGHT) - { - flipscreen(true); - } -#endif -}; - - - -void TFT_T_DMA::flipscreen(bool flip) -{ - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(TFT_MADCTL); - digitalWrite(_dc, 1); - if (flip) { - flipped=true; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB); -#endif -#endif - } - else { - flipped=false; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB); -#endif -#endif - } - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - -boolean TFT_T_DMA::isflipped(void) -{ - return(flipped); -} - - -#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) - - -void TFT_T_DMA::startDMA(void) { - curTransfer = 0; - rstop = 0; - //dmatx.begin(true); - dmatx.attachInterrupt(dmaInterrupt); - setDmaStruct(); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - - digitalWrite(_cs, HIGH); - SPI.begin(); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); - - - LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: - LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX - LPSPIP_TCR = 15; // Framesize 16 Bits - //LPSPIP_FCR = 0; // Fifo Watermark - LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable - LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: - dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); - - dmatx = dmasettings[0]; - digitalWrite(_cs, 0); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - dmatx.enable(); -} - - -void TFT_T_DMA::stopDMA(void) { - rstop = 0; - wait(); - delay(50); - cancelled = false; - dmatx.detachInterrupt(); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - SPI.end(); -#ifdef ST7789 - begin(); -#endif -#ifdef ILI9341 - SPI.begin(); - digitalWrite(_cs, 0); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - SPI.endTransaction(); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); -} - -void TFT_T_DMA::wait(void) { - rstop = 1; - unsigned long m = millis(); - cancelled = true; - while (!rstop) { - if ((millis() - m) > 100) break; - delay(10); - asm volatile("wfi"); - }; - rstop = 0; -} - -int TFT_T_DMA::get_frame_buffer_size(int *width, int *height){ - if (width != nullptr) *width = TFT_REALWIDTH; - if (height != nullptr) *height = TFT_REALHEIGHT; - return TFT_REALWIDTH; -} - - -/*********************************************************************************************** - Touch functions - ***********************************************************************************************/ -/* Code based on ... - * - * @file XPT2046.cpp - * @date 19.02.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the XPT2046 driver for Arduino. - */ - -#define ADC_MAX 0x0fff - -void TFT_T_DMA::enableTouchIrq() -{ - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 }; - SPI.transfer((void*)&buf[0],3); - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); -} - -//Default callibration for non flipped -#define TX_MIN 30 -#define TY_MIN 20 -#define TX_MAX 300 -#define TY_MAX 220 - -//Default callibration for flipped -#define TFX_MIN 20 -#define TFY_MIN 25 -#define TFX_MAX 288 -#define TFY_MAX 221 - -static uint16_t txMin; -static uint16_t tyMin; -static uint16_t txMax; -static uint16_t tyMax; - - -void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { - if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) { - txMin = xMin; - tyMin = yMin; - txMax = xMax; - tyMax = yMax; - } - else { - if (flipped) { - txMin = TFX_MIN; - tyMin = TFY_MIN; - txMax = TFX_MAX; - tyMax = TFY_MAX; - } - else { - txMin = TX_MIN; - tyMin = TY_MIN; - txMax = TX_MAX; - tyMax = TY_MAX; - } - } -} - - -void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - if ( TOUCH_ENABLED() ) { - uint16_t x = 0; - uint16_t y = 0; - uint16_t z1 = 0; - uint16_t z2 = 0; - uint8_t i = 0; - int16_t xraw=0, yraw=0; - - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - - for(; i < 15; i++) { - // SPI requirer 32bit aliment - uint8_t buf[12] = { - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00 - }; - SPI.transfer(&buf[0], &buf[0], 12); - y += (buf[1] << 8 | buf[2])>>3; - x += (buf[4] << 8 | buf[5])>>3; - z1 += (buf[7] << 8 | buf[8])>>3; - z2 += (buf[10] << 8 | buf[11])>>3; - } - enableTouchIrq(); - - if(i == 0) { - *oX = 0; - *oY = 0; - *oZ = 0; - } - else { - x /= i; - y /= i; - z1 /= i; - z2 /= i; - } - - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); - int z = z1 + ADC_MAX - z2; - if (flipped) { - xraw = x; - yraw = y; - } else { - xraw = ADC_MAX - x; - yraw = ADC_MAX - y; - } - xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1); - yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1); - - *oX = xraw; - *oY = yraw; - *oZ = z; - } - else - { - *oX = 0; - *oY = 0; - *oZ = 0; - } -} - -void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - readRaw(oX,oY,oZ); - // callibrate ... - if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin); - if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin); - //Serial.print(*oX); - //Serial.print(" "); - //Serial.println(*oY); -} - - -/*********************************************************************************************** - No DMA functions - ***********************************************************************************************/ -void TFT_T_DMA::fillScreenNoDma(uint16_t color) { - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - int i,j; - for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(arx, ary, arx+arw-1, ary+arh-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - bits = *charpt++; - //digitalWrite(_dc, 1); - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - x +=8; -#ifdef ILI9341 - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); -#endif - digitalWrite(_cs, 1); - SPI.endTransaction(); - } - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - - - -/*********************************************************************************************** - DMA functions - ***********************************************************************************************/ -uint16_t * TFT_T_DMA::getLineBuffer(int j) -{ - uint16_t * block=blocks[j>>6]; - return(&block[(j&0x3F)*TFT_REALWIDTH]); -} - -void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) { - uint8_t *buffer=buf; - uint8_t *src; - - int i,j,y=0; - if (width*2 <= TFT_REALWIDTH) { - for (j=0; j>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH]; - for (i=0; i>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x]; - for (i=0; i>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - block=blocks[l>>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt++; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - x +=8; - } -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { - drawSprite(x,y,bitmap, 0,0,0,0); -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) -{ - int bmp_offx = 0; - int bmp_offy = 0; - uint16_t *bmp_ptr; - - int w =*bitmap++; - int h = *bitmap++; - - - if ( (arw == 0) || (arh == 0) ) { - // no crop window - arx = x; - ary = y; - arw = w; - arh = h; - } - else { - if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - int l=ary; - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx]; - bmp_ptr = (uint16_t*)bitmap; - for (int col=0;col -#include -#include -#endif - -#include "tft_t_dma_config.h" - -#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) -#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define R16(rgb) ((rgb>>8)&0xf8) -#define G16(rgb) ((rgb>>3)&0xfc) -#define B16(rgb) ((rgb<<3)&0xf8) - -#define PAL_COLOR_MASK 0xff - -#ifdef LOHRES -#define TFT_WIDTH 240 -#define TFT_REALWIDTH 240 -#else -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 -#endif -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - -//#define WIDTH 272 -//#define HEIGHT 228 - -#define LINES_PER_BLOCK 64 -#define NR_OF_BLOCK 4 -#define SCREEN_DMA_NUM_SETTINGS NR_OF_BLOCK - - -#ifdef ILI9341 - -#define ILI9341_NOP 0x00 -#define ILI9341_SWRESET 0x01 -#define ILI9341_RDDID 0x04 -#define ILI9341_RDDST 0x09 - -#define ILI9341_SLPIN 0x10 -#define ILI9341_SLPOUT 0x11 -#define ILI9341_PTLON 0x12 -#define ILI9341_NORON 0x13 - -#define ILI9341_RDMODE 0x0A -#define ILI9341_RDMADCTL 0x0B -#define ILI9341_RDPIXFMT 0x0C -#define ILI9341_RDIMGFMT 0x0D -#define ILI9341_RDSELFDIAG 0x0F - -#define ILI9341_INVOFF 0x20 -#define ILI9341_INVON 0x21 -#define ILI9341_GAMMASET 0x26 -#define ILI9341_DISPOFF 0x28 -#define ILI9341_DISPON 0x29 - -#define ILI9341_CASET 0x2A -#define ILI9341_PASET 0x2B -#define ILI9341_RAMWR 0x2C -#define ILI9341_RAMRD 0x2E - -#define ILI9341_PTLAR 0x30 -#define ILI9341_MADCTL 0x36 -#define ILI9341_VSCRSADD 0x37 -#define ILI9341_PIXFMT 0x3A - -#define ILI9341_FRMCTR1 0xB1 -#define ILI9341_FRMCTR2 0xB2 -#define ILI9341_FRMCTR3 0xB3 -#define ILI9341_INVCTR 0xB4 -#define ILI9341_DFUNCTR 0xB6 - -#define ILI9341_PWCTR1 0xC0 -#define ILI9341_PWCTR2 0xC1 -#define ILI9341_PWCTR3 0xC2 -#define ILI9341_PWCTR4 0xC3 -#define ILI9341_PWCTR5 0xC4 -#define ILI9341_VMCTR1 0xC5 -#define ILI9341_VMCTR2 0xC7 - -#define ILI9341_RDID1 0xDA -#define ILI9341_RDID2 0xDB -#define ILI9341_RDID3 0xDC -#define ILI9341_RDID4 0xDD - -#define ILI9341_GMCTRP1 0xE0 -#define ILI9341_GMCTRN1 0xE1 - -#define ILI9341_MADCTL_MY 0x80 -#define ILI9341_MADCTL_MX 0x40 -#define ILI9341_MADCTL_MV 0x20 -#define ILI9341_MADCTL_ML 0x10 -#define ILI9341_MADCTL_RGB 0x00 -#define ILI9341_MADCTL_BGR 0x08 -#define ILI9341_MADCTL_MH 0x04 - -#define TFT_CASET ILI9341_CASET -#define TFT_PASET ILI9341_PASET -#define TFT_RAMWR ILI9341_RAMWR -#define TFT_MADCTL ILI9341_MADCTL - -#endif - - -#ifdef ST7789 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_RGB 0x00 -#define ST77XX_MADCTL_BGR 0x08 -#define ST77XX_MADCTL_MH 0x04 - -#define TFT_CASET ST7735_CASET -#define TFT_PASET ST7735_RASET -#define TFT_RAMWR ST7735_RAMWR -#define TFT_MADCTL ST7735_MADCTL - -#endif - - - -#ifdef __cplusplus - -class TFT_T_DMA -{ - public: - TFT_T_DMA(uint8_t _CS, uint8_t _DC, uint8_t _RST = 255, uint8_t _MOSI=11, uint8_t _SCLK=13, uint8_t _MISO=12, uint8_t touch_cs=38, uint8_t touch_irq=37); - - void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); - void begin(void); - void flipscreen(bool flip); - boolean isflipped(void); - void startDMA(void); - void stopDMA(); - int get_frame_buffer_size(int *width, int *height); - - // Touch screen functions - #define TOUCH_ENABLED() ((_touch_cs != 255) && (_touch_irq != 255)) - bool isTouching(void) { return ((!TOUCH_ENABLED())?false:(digitalRead(_touch_irq) == LOW)); } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax); - - // NoDMA functions - void writeScreenNoDma(const uint16_t *pcolors); - void fillScreenNoDma(uint16_t color); - void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - // DMA functions - uint16_t * getLineBuffer(int j); - void writeScreen(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int y, uint16_t *buf); - void fillScreen(uint16_t color); - void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - protected: - uint8_t _rst, _cs, _dc; - uint8_t _miso, _mosi, _sclk; - uint8_t _touch_irq=255, _touch_cs=255; - bool flipped=false; - - void wait(void); - void enableTouchIrq(); -}; - -#endif -#endif - - diff --git a/MCUME_teensy41/teecomputerkeytest/tft_t_dma_config.h b/MCUME_teensy41/teecomputerkeytest/tft_t_dma_config.h deleted file mode 100644 index 354cf74..0000000 --- a/MCUME_teensy41/teecomputerkeytest/tft_t_dma_config.h +++ /dev/null @@ -1,14 +0,0 @@ -#include "platform_config.h" - -//#define ST7789 1 -//#define ILI9341 1 - -#define TFT_LINEARINT 1 -#define LINEARINT_HACK 1 - -//#define FLIP_SCREEN 1 -//#define TFT_DEBUG 1 -#if defined(__IMXRT1052__) || defined(__IMXRT1062__) -//#define TFT_STATICFB 1 -#endif - diff --git a/MCUME_teensy41/teecomputerkeytest/vga_t_dma.h b/MCUME_teensy41/teecomputerkeytest/vga_t_dma.h deleted file mode 100644 index e396ba1..0000000 --- a/MCUME_teensy41/teecomputerkeytest/vga_t_dma.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - Wrapping class to extend VGA_T4 to TFT_T_DMA -*/ - -#ifndef _VGA_T_DMAH_ -#define _VGA_T_DMAH_ - -#ifdef __cplusplus -#include -#endif - - -#define RGBVAL16(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) - - - -#ifdef HIRES -#define TFT_WIDTH 640 -#define TFT_REALWIDTH 640 -#else -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 -#endif - -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - - - -#ifdef __cplusplus - -class TFT_T_DMA: public VGA_T4 -{ - public: - // Fake touch screen functions - bool isTouching(void) { return false; } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { } - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { }; - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { } - - // fake DMA functions - void startDMA(void) { }; - void stopDMA(void) { }; - - // fake no DMA functions - void writeScreenNoDma(const vga_pixel *pcolors) { writeScreen(pcolors); } - void fillScreenNoDma(vga_pixel color) { clear(color); } - void drawTextNoDma(int16_t x, int16_t y, const char * text, vga_pixel fgcolor, vga_pixel bgcolor, bool doublesize) { drawText(x,y,text,fgcolor,bgcolor,doublesize); } - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, vga_pixel color) { drawRect(x, y, w, h, color); } - void drawSpriteNoDma(int16_t x, int16_t y, const int16_t *bitmap) { drawSprite(x, y, bitmap); } - void drawSpriteNoDma(int16_t x, int16_t y, const int16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh) { drawSprite(x, y, bitmap, croparx, cropary, croparw, croparh); } -}; - - -#endif -#endif diff --git a/MCUME_teensy41/teensy20/MOS6561.cpp b/MCUME_teensy41/teensy20/MOS6561.cpp index da9644b..656b65e 100644 --- a/MCUME_teensy41/teensy20/MOS6561.cpp +++ b/MCUME_teensy41/teensy20/MOS6561.cpp @@ -5,18 +5,10 @@ extern "C" { #include "platform_config.h" } -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -typedef uint8_t Pixel; -#else -#include "tft_t_dma.h" typedef uint16_t Pixel; -#endif -#define WIN_W TFT_WIDTH -#define WIN_H TFT_HEIGHT - -//#include +#define WIN_W 320 //TFT_WIDTH +#define WIN_H 240 //TFT_HEIGHT // definitions for easy access to registers @@ -70,6 +62,8 @@ static uint16_t remap[16] = { 0x1c00 }; +static Pixel linebuf[WIN_W]; + MOS6561::MOS6561() : IC(), curRow(0), frameReady(true) { // Set clock speed this->setClockSpeed(1108000); @@ -102,10 +96,11 @@ void MOS6561::initialize() { void MOS6561::renderBorder(uint16_t raster){ if (raster < WIN_H) { Pixel bcol = vicPalette[REG_BORDER_COLOUR]; - Pixel * dst = (Pixel *)emu_LineBuffer(raster); + Pixel * dst = &linebuf[0]; for (int x=0; x < WIN_W; x++) { *dst++ = bcol; - } + } + emu_DrawLine16(&linebuf[0], WIN_W, WIN_H, raster); } } @@ -137,7 +132,7 @@ void MOS6561::renderLine(uint16_t raster, uint16_t row, uint8_t rowHeight, uint8 cols[bakcol] = vicPalette[REG_BACKGROUND_COLOUR]; // Border Left - Pixel * dst = (Pixel *)emu_LineBuffer(raster); + Pixel * dst = &linebuf[0]; for (int x=0; x < bWidth; x++) { *dst++ = cols[borcol]; } @@ -179,7 +174,8 @@ void MOS6561::renderLine(uint16_t raster, uint16_t row, uint8_t rowHeight, uint8 // Border Right for (int x=0; x < bWidth; x++) { *dst++ = cols[borcol]; - } + } + emu_DrawLine16(&linebuf[0], WIN_W, 1, raster); } } @@ -214,7 +210,7 @@ void MOS6561::renderRow(uint16_t raster, uint16_t row, uint8_t rowHeight) for (int line=0; line < rowHeight; line++) { // Border Left - Pixel * dst = (Pixel *)emu_LineBuffer(curRow*rowHeight+line+raster); + Pixel * dst = &linebuf[0]; for (int x=0; x < bWidth; x++) { *dst++ = cols[borcol]; } @@ -230,25 +226,25 @@ void MOS6561::renderRow(uint16_t raster, uint16_t row, uint8_t rowHeight) uint8_t multiColour = colPointer[x] & 0x8; cols[forcol] = vicPalette[colour]; if (!multiColour) { - Pixel * dest = dst; - for (int a = 0; a < 8; a++) { - if ((characterByte << a) & 0x80) { - *dest++ = cols[forcol]; - } - else { - *dest++ = cols[bakcol]; - } - } + Pixel * dest = dst; + for (int a = 0; a < 8; a++) { + if ((characterByte << a) & 0x80) { + *dest++ = cols[forcol]; + } + else { + *dest++ = cols[bakcol]; + } + } } else { - Pixel * dest = dst; - cols[auxcol] = vicPalette[REG_AUXILIARY_COLOUR]; - for (int a = 0; a < 8; a += 2) { - // Set colour - Pixel col = cols[((characterByte << a) & 0xC0) >> 6]; - *dest++ = col; - *dest++ = col; - } + Pixel * dest = dst; + cols[auxcol] = vicPalette[REG_AUXILIARY_COLOUR]; + for (int a = 0; a < 8; a += 2) { + // Set colour + Pixel col = cols[((characterByte << a) & 0xC0) >> 6]; + *dest++ = col; + *dest++ = col; + } } dst +=8; } @@ -256,7 +252,8 @@ void MOS6561::renderRow(uint16_t raster, uint16_t row, uint8_t rowHeight) // Border Right for (int x=0; x < bWidth; x++) { *dst++ = cols[borcol]; - } + } + emu_DrawLine16(&linebuf[0], WIN_W, 1, curRow*rowHeight+line+raster); } } } diff --git a/MCUME_teensy41/teensy20/emuapi.cpp b/MCUME_teensy41/teensy20/emuapi.cpp index c367cb0..e128cca 100644 --- a/MCUME_teensy41/teensy20/emuapi.cpp +++ b/MCUME_teensy41/teensy20/emuapi.cpp @@ -5,25 +5,31 @@ extern "C" { #include "iopins.h" } -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#else -#include "tft_t_dma.h" -#endif +#include -#ifdef HAS_USBKEY +#ifdef HAS_USB #include "USBHost_t36.h" // Read this header first for key info USBHost myusb; USBHub hub1(myusb); +#ifdef HAS_USBKEY KeyboardController keyboard1(myusb); USBHIDParser hid1(myusb); MouseController mouse1(myusb); +#endif +#ifdef HAS_USBMIDI MIDIDevice midi1(myusb); #endif +#ifdef HAS_USBJOY +#define COUNT_JOYSTICKS 4 +JoystickController joysticks[COUNT_JOYSTICKS](myusb); +#endif +#endif static bool emu_writeConfig(void); static bool emu_readConfig(void); static bool emu_eraseConfig(void); +static bool emu_writeGfxConfig(char * display_type); +static int emu_readGfxConfig(void); static bool mouseDetected = false; static bool keyboardDetected = false; @@ -34,12 +40,13 @@ static File file; #define MAX_FILES 64 #define AUTORUN_FILENAME "autorun.txt" +#define GFX_CFG_FILENAME "gfxmode.txt" -#define MAX_FILENAME_SIZE 24 +#define MAX_FILENAME_SIZE 34 #define MAX_MENULINES 9 #define TEXT_HEIGHT 16 #define TEXT_WIDTH 8 -#define MENU_FILE_XOFFSET (6*TEXT_WIDTH) +#define MENU_FILE_XOFFSET (2*TEXT_WIDTH) #define MENU_FILE_YOFFSET (2*TEXT_HEIGHT) #define MENU_FILE_W (MAX_FILENAME_SIZE*TEXT_WIDTH) #define MENU_FILE_H (MAX_MENULINES*TEXT_HEIGHT) @@ -53,7 +60,8 @@ static File file; #define MENU_VGA_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) #define MENU_VGA_YOFFSET (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37) -extern TFT_T_DMA tft; +#include "t4_dsp.h" +T4_DSP tft; static int nbFiles=0; static int curFile=0; @@ -65,6 +73,8 @@ static char selected_filename[MAX_FILENAME_SIZE]=""; static char second_selected_filename[MAX_FILENAME_SIZE]=""; static bool menuRedraw=true; static bool autorun=false; +static bool vgahires=false; + static const unsigned short * keys; #ifdef TEECOMPUTER @@ -158,6 +168,29 @@ void emu_Free(void * pt) free(pt); } +#define SMEMPOOL (0x800000) +EXTMEM static unsigned char slowmem[SMEMPOOL]; +static int slowmempt = 0; + +void * emu_SMalloc(unsigned int size) +{ + void * mem = (void*)&slowmem[slowmempt]; + slowmempt += size; + + if ( slowmempt > SMEMPOOL ) { + mem = NULL; + emu_printf("failure to allocate slow"); + } + else { + emu_printf("could allocate slow static "); + emu_printf(size); + } + return mem; +} + +void emu_SFree(void * pt) +{ +} /******************************** * Input and keyboard ********************************/ @@ -329,6 +362,12 @@ int emu_ReadKeys(void) #endif if ( row & 0x02 ) retval |= MASK_JOY2_BTN; + +#ifdef EXTPAD + if ( sh_pressed ) retval |= MASK_KEY_USER3; + if ( fn_pressed ) retval |= MASK_KEY_USER1; + digitalWrite(KLED, 0); +#else // Handle LED flash uint32_t time_ms=millis(); if ((time_ms-last_t_ms) > 100) { @@ -412,8 +451,9 @@ int emu_ReadKeys(void) if ( key_fn ) retval |= MASK_KEY_USER2; if ( ( key_fn ) && (keymatrix[4] == 0x10 )) retval |= MASK_KEY_USER1; +#endif - if ( (key_fn) && (key_sh) ) + if ( (fn_pressed) && (sh_pressed) ) #else if ( ((retval & (MASK_KEY_USER1+MASK_KEY_USER2)) == (MASK_KEY_USER1+MASK_KEY_USER2)) || (retval & MASK_KEY_USER4 ) ) @@ -453,8 +493,10 @@ int emu_ReadKeys(void) while (true) { ; } -#endif +#endif } + + emu_GetJoystick(); return (retval); } @@ -607,7 +649,7 @@ int emu_setKeymap(int index) { } int emu_GetMouse(int *x, int *y, int *buts) { -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBKEY) if (mouse1.available()) { *buts = mouse1.getButtons(); *x = mouse1.getMouseX(); @@ -620,7 +662,23 @@ int emu_GetMouse(int *x, int *y, int *buts) { return 0; } -#ifdef HAS_USBKEY +int emu_GetJoystick(void) { +#if defined(HAS_USB) && (HAS_USBJOY) + for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) { + if (joysticks[joystick_index].available()) { + uint64_t axis_mask = joysticks[joystick_index].axisMask(); + uint64_t axis_changed_mask = joysticks[joystick_index].axisChangedMask(); + uint32_t buttons = joysticks[joystick_index].getButtons(); + Serial.printf("Joystick(%d): buttons = %x", joystick_index, buttons); + Serial.println(); + } + } + return 1; +#endif + return 0; +} + +#if defined(HAS_USB) && (HAS_USBKEY) void OnPress(auto key) { keyboardDetected = true; @@ -764,7 +822,7 @@ int emu_KeyboardDetected(void) { return (keyboardDetected?1:0); } -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) static unsigned char midiBuffer[16]; static unsigned char midiLastCmd=0; static int midiDataCnt=0; @@ -772,8 +830,7 @@ static int midiCmdNbParam=0; #endif void emu_MidiOnDataReceived(unsigned char value) { - -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) //Serial.println(value, HEX); //10000000 = 128 = note off //10010000 = 144 = note on @@ -941,6 +998,7 @@ void emu_MidiOnDataReceived(unsigned char value) { /******************************** * Menu file loader UI ********************************/ +#ifdef FILEBROWSER static int readNbFiles(void) { int totalFiles = 0; @@ -970,8 +1028,6 @@ static int readNbFiles(void) { return totalFiles; } - - void backgroundMenu(void) { menuRedraw=true; tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00)); @@ -981,11 +1037,13 @@ void backgroundMenu(void) { int handleMenu(uint16_t bClick) { if (autorun) { + toggleMenu(false); + menuRedraw=false; return (ACTION_RUN1); } int action = ACTION_NONE; - if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) ) { + if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) || ( bClick & MASK_KEY_USER2 ) ) { char newpath[MAX_FILENAME_PATH]; strcpy(newpath, selection); strcat(newpath, "/"); @@ -996,17 +1054,31 @@ int handleMenu(uint16_t bClick) File file = SD.open(selection); if (file.isDirectory()) { curFile = 0; - nbFiles = readNbFiles(); + nbFiles = readNbFiles(); + menuRedraw=true; } - else { - action = ACTION_RUN1; + else + { #ifdef TEECOMPUTER - if (key_extmode) { + if ( (key_extmode) || ( key_sh) ) { emu_writeConfig(); } + if ( tft.getMode() < MODE_VGA_320x240) { + if ( bClick & MASK_KEY_USER2 ) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + } + //emu_SwapJoysticks(0); #endif + toggleMenu(false); + menuRedraw=false; + return (ACTION_RUN1); } - menuRedraw=true; } else if ( bClick & MASK_KEY_USER1 ) { menuRedraw=true; @@ -1015,19 +1087,14 @@ int handleMenu(uint16_t bClick) strcat(second_selection, "/"); strcat(second_selection, second_selected_filename); action = ACTION_RUN2; - } - else if ( bClick & MASK_KEY_USER2 ) { - menuRedraw=true; - //action = ACTION_RUN3; - emu_SwapJoysticks(0); - } + } else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) { if (curFile!=0) { menuRedraw=true; curFile--; } } - else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { + else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { if ((curFile-9)>=0) { menuRedraw=true; curFile -= 9; @@ -1042,7 +1109,7 @@ int handleMenu(uint16_t bClick) menuRedraw=true; } } - else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { + else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { if ((curFile<(nbFiles-9)) && (nbFiles)) { curFile += 9; menuRedraw=true; @@ -1099,12 +1166,12 @@ int handleMenu(uint16_t bClick) return (action); } -bool menuActive(void) +int menuActive(void) { - return (menuOn); + return (menuOn?1:0); } -void toggleMenu(bool on) { +void toggleMenu(int on) { if (on) { menuOn=true; backgroundMenu(); @@ -1122,7 +1189,7 @@ char * menuSecondSelection(void) { return (second_selection); } - +#endif /******************************** * OSKB handling @@ -1140,8 +1207,9 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) char c[4] = {' ',0,' ',0}; const char * cpt = str; int i=0; - int fb_width,fb_height; - tft.get_frame_buffer_size(&fb_width, &fb_height); + int fb_width,fb_height,fbstride; + + fbstride = tft.get_frame_buffer_size(&fb_width, &fb_height); int ypos = (bottom?(fb_height-2*8):0); int line = row + (bottom?2:0); while ((c[1] = *cpt++)) @@ -1150,7 +1218,7 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0); else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff); if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff); - tft.drawTextNoDma(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); + tft.drawText(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); i++; } } @@ -1248,7 +1316,7 @@ int handleOSKB(void) { return retval; } -void toggleOSKB(bool forceon) { +void toggleOSKB(int forceon) { if (forceon) { oskbOn = true; drawOSKB(); @@ -1332,6 +1400,17 @@ int emu_FileRead(void * buf, int size, int handler) #endif } +int emu_FileWrite(void * buf, int size, int handler) +{ +// emu_printf("emu_FileWrite"); +// emu_printi(handler); +#ifdef HCFH + return (file.write(buf, size)); +#else + return (getFileHandler(handler).write(buf, size)); +#endif +} + int emu_FileGetc(int handler) { // emu_printf("FileGetc"); // emu_printi(handler); @@ -1404,6 +1483,9 @@ unsigned int emu_FileSize(const char * filepath) emu_printf(filesize); lofile.close(); } + else { + emu_printf("filesize failed"); + } return(filesize); } @@ -1489,6 +1571,48 @@ static bool emu_eraseConfig(void) SD.remove (ROMSDIR "/" AUTORUN_FILENAME); } +static bool emu_writeGfxConfig(char * display_type) +{ + bool retval = false; + SD.remove ("/" GFX_CFG_FILENAME); + if (strcmp(display_type, "VGA")) { + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(display_type, strlen(display_type)) != strlen(display_type)) { + emu_printf("GFX config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + } + return retval; +} + +#define CFG_VGA 0 +#define CFG_ILI 1 +#define CFG_ST 2 + +static int emu_readGfxConfig(void) +{ + int retval = CFG_VGA; // No file = VGA + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + if (filesize == 2) // "ST" + { + retval = CFG_ST; + } + else if (filesize == 3) // "ILI" + { + retval = CFG_ILI; + } + lofile.close(); + } + return retval; +} + /******************************** * File IO compatibility ********************************/ @@ -1670,62 +1794,249 @@ FRESULT f_mkdir (const char* path) /******************************** - * Initialization + * GFX wrapper ********************************/ -void emu_init(void) +static unsigned short palette16[PALETTE_SIZE]; +static IntervalTimer myTimer; +volatile boolean vbl=true; +volatile boolean vgatimervsync=false; +static void (*vblCallback)(void) = nullptr; +static int skip=0; + +static void vblCount() { + if (vbl) { + vbl = false; + } else { + vbl = true; + } +} + +void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) +{ + if (index= MODE_VGA_320x240 ) { + if (vgatimervsync) { + while (vbl==vb) {}; + } + else { + tft.waitSync(); + } + } + else { + while (vbl==vb) {}; + } + if (vblCallback != nullptr) { + vblCallback(); + } +} + +void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride) +{ + if (skip == 0) { + tft.writeScreenPal(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); + } +} +void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLinePal(width,height,line, VBuf, palette16); + } +} + +void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine(width,height,line, VBuf); + } +} + +void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine8(width,height,line, VBuf, palette16); + } +} + +int emu_IsVga(void) +{ + return (tft.getMode() >= MODE_VGA_320x240?1:0); +} + +int emu_IsVgaHires(void) +{ + return (tft.getMode() >= MODE_VGA_640x240?1:0); +} + +int emu_FrameSkip(void) +{ + return skip; +} + + +/******************************** + * AUDIO wrapper +********************************/ +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +AudioPlaySystem mymixer; + +void emu_sndInit() { + Serial.println("sound init"); + mymixer.begin_audio(256, mymixer.snd_Mixer); + mymixer.start(); +} + +void emu_sndPlaySound(int chan, int volume, int freq) +{ + if (chan < 6) { + mymixer.sound(chan, freq, volume); + } + /* + Serial.print(chan); + Serial.print(":" ); + Serial.print(volume); + Serial.print(":" ); + Serial.println(freq); + */ +} + +void emu_sndPlayBuzz(int size, int val) { + mymixer.buzz(size,val); + //Serial.print((val==1)?1:0); + //Serial.print(":"); + //Serial.println(size); +} +#endif + +/******************************** + * Initialization +********************************/ +void emu_init(int hires) { Serial.begin(115200); + vgahires = hires; -#ifdef HAS_USBKEY +#ifdef HAS_USB myusb.begin(); +#ifdef HAS_USBKEY keyboard1.attachPress(OnPress); keyboard1.attachRelease(OnRelease); #endif +#endif - while (!SD.begin(SD_CS)) +#ifdef FILEBROWSER + if (!SD.begin(SD_CS)) { - Serial.println("SD begin failed, retrying..."); - delay(1000); + Serial.println("No SD card detected"); } strcpy(selection,ROMSDIR); - FileHandlersInit(); - nbFiles = readNbFiles(); - - Serial.print("SD initialized, files found: "); Serial.println(nbFiles); +#endif emu_InitJoysticks(); #ifdef SWAP_JOYSTICK - joySwapped = true; + joySwapped = true; #else - joySwapped = false; + joySwapped = false; #endif -#ifdef TEECOMPUTER -#ifndef HAS_T4_VGA - tft.flipscreen(false); -#endif -#endif int keypressed = emu_ReadKeys(); +#ifdef HAS_T4_VGA + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } +#else + int gfx_mode = CFG_VGA; // default +#ifdef FILEBROWSER + gfx_mode = emu_readGfxConfig(); +#endif + // Force VGA if UP pressed + if (keypressed & MASK_JOY2_UP) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("VGA"); +#endif + gfx_mode = CFG_VGA; + } + else { + if (keypressed & MASK_JOY2_LEFT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ST"); +#endif + gfx_mode = CFG_ST; + } + else if (keypressed & MASK_JOY2_RIGHT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ILI"); +#endif + gfx_mode = CFG_ILI; + } + } + if (gfx_mode == CFG_VGA) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + else + { + tft.begin(gfx_mode == CFG_ILI?MODE_TFTILI_320x240:MODE_TFTST_320x240); + } +#endif + if (keypressed & MASK_JOY2_DOWN) { tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) ); tft.drawTextNoDma(64,48, (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); +#ifdef FILEBROWSER emu_eraseConfig(); delay(1000); +#endif } else { +#ifdef FILEBROWSER if (emu_readConfig()) { autorun = true; } +#endif } +#ifdef FILEBROWSER toggleMenu(true); +#endif } -void emu_start(void) +void emu_start(int vblms, void * callback, int forcetimervsync) { + vgatimervsync = forcetimervsync?true:false; + tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); + tft.startRefresh(); + if (callback != nullptr) { + vblCallback = callback; + } + + myTimer.begin(vblCount, vblms); +#ifdef HAS_SND + emu_sndInit(); +#endif usbnavpad = 0; } diff --git a/MCUME_teensy41/teensy20/emuapi.h b/MCUME_teensy41/teensy20/emuapi.h index e4c941b..5dd6130 100644 --- a/MCUME_teensy41/teensy20/emuapi.h +++ b/MCUME_teensy41/teensy20/emuapi.h @@ -2,126 +2,14 @@ #define EMUAPI_H #include "platform_config.h" - -#define CUSTOM_SND 1 -//#define TIMER_REND 1 - -#define EXTRA_HEAP 0x10 - -// Title: < > -#define TITLE " Vic20 Emulator " -#define ROMSDIR "v20" - -#define emu_Init(ROM) { v20_Init(); v20_Start(ROM);} -#define emu_Step(x) { v20_Step(); } -#define emu_Input(x) { v20_Input(x); } - -#define MAX_FILENAME_PATH 64 -#define NB_FILE_HANDLER 4 -#define PALETTE_SIZE 256 -#define VID_FRAME_SKIP 0x0 -#define TFT_VBUFFER_YCROP 0 -#define SINGLELINE_RENDERING 1 - -#define R32(rgb) ((rgb>>16)&0xff) -#define G32(rgb) ((rgb>>8)&0xff) -#define B32(rgb) (rgb & 0xff) +#include "emucfg.h" #define ACTION_NONE 0 -#define ACTION_MAXKBDVAL 16 -#define ACTION_EXITKBD 128 -#define ACTION_RUN1 129 -#define ACTION_RUN2 130 -#define ACTION_RUN3 131 - - -#ifdef KEYMAP_PRESENT - -#define keylables_map0_0 (char *)"QWERTYUIOP\x1a" -#define keylables_map0_1 (char *)" ASDFGHJKL\x19" -#define keylables_map0_2 (char *)" ZXCVBNM,.;/" -#define keylables_map0_3 (char *)" +\x10-" -const unsigned short key_map0[] = { - 'Q','W','E','R','T','Y','U','I','O','P',157, //default C64 uppercase always - 0,'A','S','D','F','G','H','J','K','L',10, - 0,'Z','X','C','V','B','N','M',',','.',';','/', - 0,0,0,0, - 0,'+',' ','-' - }; - -#define keylables_map1_0 (char *)"1234567890 " -#define keylables_map1_1 (char *)" " -#define keylables_map1_2 (char *)" " -#define keylables_map1_3 (char *)" " - -const unsigned short key_map1[] = { - '1','2','3','4','5','6','7','8','9','0',0, // digit keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map2_0 (char *)"!\"#$%^&*()@" -#define keylables_map2_1 (char *)" " -#define keylables_map2_2 (char *)" <>:?" -#define keylables_map2_3 (char *)" =\x10_" -const unsigned short key_map2[] = { - '!','"','#','$','%','^','&','*','(',')','@', // shiftothers - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,'<','>',':','?', - 153,151,150,152, //U L R D - 0,'=',' ','_' - }; - -#define keylables_map3_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " -#define keylables_map3_1 (char *)" " -#define keylables_map3_2 (char *)" " -#define keylables_map3_3 (char *)" " - -const unsigned short key_map3[] = { - 129,130,131,132,133,134,135,136,0,0,0, // function keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map4_0 (char *)"QWERTYUIOP@" -#define keylables_map4_1 (char *)" ASDFGHJKL\x19" -#define keylables_map4_2 (char *)" ZXCVBNM<>:?" -#define keylables_map4_3 (char *)" =\x10_" -const unsigned short key_map4[] = { - 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase - 0,'A','S','D','F','G','H','J','K','L',10, - 0,'Z','X','C','V','B','N','M','<','>',':','?', - 0,0,0,0, - 0,'=',' ','_' - }; - -#define keylables_map5_0 (char *)" " -#define keylables_map5_1 (char *)" " -#define keylables_map5_2 (char *)" " -#define keylables_map5_3 (char *)" " - -const unsigned short key_map5[] = { - 0,0,0,0,0,0,0,0,0,0,0, // extra keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 153,151,150,152, //U L R D - 0,0,' ',0 - }; - -const unsigned short matkeys[] = { - 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 - 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 - 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 - 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN - 0x510,0x010,0x110,0x310, // row 4 - }; - -#endif +#define ACTION_RUN1 1 +#define ACTION_RUN2 2 +#define FORCE_VGATIMERVSYNC 1 +#define SUPPORT_HIRES 1 #define MASK_JOY2_RIGHT 0x0001 #define MASK_JOY2_LEFT 0x0002 @@ -138,22 +26,25 @@ const unsigned short matkeys[] = { #define MASK_JOY1_BTN 0x1000 #define MASK_KEY_USER4 0x2000 +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) #ifdef __cplusplus extern "C" { +extern void emu_init(int hires=0); +extern void emu_start(int vblms, void * callback, int forcetimervsync=0); #endif - -extern void emu_init(void); -extern void emu_start(void); extern void emu_printf(const char * text); extern void emu_printi(int val); extern void emu_printh(int val); extern void * emu_Malloc(unsigned int size); extern void * emu_MallocI(unsigned int size); extern void emu_Free(void * pt); +extern void * emu_SMalloc(unsigned int size); +extern void emu_SFree(void * pt); extern int emu_FileOpen(const char * filepath, const char * mode); extern int emu_FileRead(void * buf, int size, int handler); +extern int emu_FileWrite(void * buf, int size, int handler); extern int emu_FileGetc(int handler); extern int emu_FileSeek(int handler, int seek, int origin); extern int emu_FileTell(int handler); @@ -164,24 +55,23 @@ extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size); extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek); extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index); -extern void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride); -extern void emu_DrawLine(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line); extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line); +extern void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride); extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line); -extern void emu_CopyLine(int width, int height, int ysrc, int ydst); extern void emu_DrawVsync(void); extern int emu_FrameSkip(void); -extern void * emu_LineBuffer(int line); -extern void emu_tweakVideo(int shiftdelta, int numdelta, int denomdelta); +extern int emu_IsVga(void); +extern int emu_IsVgaHires(void); -extern bool menuActive(void); +extern int menuActive(void); extern char * menuSelection(void); extern char * menuSecondSelection(void); -extern void toggleMenu(bool on); +extern void toggleMenu(int on); extern int handleMenu(unsigned short bClick); extern int handleOSKB(void); -extern void toggleOSKB(bool forceon); +extern void toggleOSKB(int forceon); extern void emu_InitJoysticks(void); extern int emu_SwapJoysticks(int statusOnly); @@ -190,6 +80,7 @@ extern int emu_ReadKeys(void); extern int emu_GetPad(void); extern int emu_GetMouse(int *x, int *y, int *buts); extern int emu_MouseDetected(void); +extern int emu_GetJoystick(void); extern int emu_KeyboardDetected(void); extern int emu_ReadAnalogJoyX(int min, int max); extern int emu_ReadAnalogJoyY(int min, int max); diff --git a/MCUME_teensy41/teensy20/emucfg.h b/MCUME_teensy41/teensy20/emucfg.h new file mode 100644 index 0000000..1e3ba26 --- /dev/null +++ b/MCUME_teensy41/teensy20/emucfg.h @@ -0,0 +1,115 @@ +#ifndef EMUCFG_H +#define EMUCFG_H + +#include "wrapemu.h" + +// Title: < > +#define TITLE " Vic20 Emulator " +#define ROMSDIR "v20" + +#define emu_Init(ROM) { v20_Init(); v20_Start(ROM);} +#define emu_Step(x) { v20_Step(); } +#define emu_Input(x) { v20_Input(x); } + +#define MAX_FILENAME_PATH 64 +#define NB_FILE_HANDLER 4 + +#define PALETTE_SIZE 16 +#define VID_FRAME_SKIP 0x0 +#define TFT_VBUFFER_YCROP 0 +#define SINGLELINE_RENDERING 1 +#define CUSTOM_SND 1 +//#define TIMER_REND 1 +//#define EXTPAD 1 +#define EXTRA_HEAP 0x10 +#define FILEBROWSER 1 + + +#ifdef KEYMAP_PRESENT + +#define keylables_map0_0 (char *)"QWERTYUIOP\x1a" +#define keylables_map0_1 (char *)" ASDFGHJKL\x19" +#define keylables_map0_2 (char *)" ZXCVBNM,.;/" +#define keylables_map0_3 (char *)" +\x10-" +const unsigned short key_map0[] = { + 'Q','W','E','R','T','Y','U','I','O','P',151, //default C64 uppercase always + 0,'A','S','D','F','G','H','J','K','L',10, + 0,'Z','X','C','V','B','N','M',',','.',';','/', + 0,0,0,0, + 0,'+',' ','-' + }; + +#define keylables_map1_0 (char *)"1234567890 " +#define keylables_map1_1 (char *)" " +#define keylables_map1_2 (char *)" " +#define keylables_map1_3 (char *)" " + +const unsigned short key_map1[] = { + '1','2','3','4','5','6','7','8','9','0',0, // digit keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 153,151,150,152, //U L R D + 0,0,' ',0 + }; + +#define keylables_map2_0 (char *)"!\"#$%^&*()@" +#define keylables_map2_1 (char *)" " +#define keylables_map2_2 (char *)" <>:?" +#define keylables_map2_3 (char *)" =\x10_" +const unsigned short key_map2[] = { + '!','"','#','$','%','^','&','*','(',')','@', // shiftothers + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 153,151,150,152, //U L R D + 0,'=',' ','_' + }; + +#define keylables_map3_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " +#define keylables_map3_1 (char *)" " +#define keylables_map3_2 (char *)" " +#define keylables_map3_3 (char *)" " + +const unsigned short key_map3[] = { + 129,130,131,132,133,134,135,136,0,0,0, // function keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 153,151,150,152, //U L R D + 0,0,' ',0 + }; + +#define keylables_map4_0 (char *)"QWERTYUIOP@" +#define keylables_map4_1 (char *)" ASDFGHJKL\x19" +#define keylables_map4_2 (char *)" ZXCVBNM<>:?" +#define keylables_map4_3 (char *)" =\x10_" +const unsigned short key_map4[] = { + 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase + 0,'A','S','D','F','G','H','J','K','L',10, + 0,'Z','X','C','V','B','N','M','<','>',':','?', + 0,0,0,0, + 0,'=',' ','_' + }; + +#define keylables_map5_0 (char *)" " +#define keylables_map5_1 (char *)" " +#define keylables_map5_2 (char *)" " +#define keylables_map5_3 (char *)" " + +const unsigned short key_map5[] = { + 0,0,0,0,0,0,0,0,0,0,0, // extra keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +const unsigned short matkeys[] = { + 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 + 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 + 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 + 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN + 0x510,0x010,0x110,0x310, // row 4 + }; + +#endif + +#endif diff --git a/MCUME_teensy41/teensy20/platform_config.h b/MCUME_teensy41/teensy20/platform_config.h index a27370c..914d152 100644 --- a/MCUME_teensy41/teensy20/platform_config.h +++ b/MCUME_teensy41/teensy20/platform_config.h @@ -4,13 +4,13 @@ #define TEECOMPUTER 1 #ifdef TEECOMPUTER -//#define ILI9341 1 -//#define ST7789 1 -//#define TFTSPI1 1 -#define HAS_T4_VGA 1 +#define TFTSPI1 1 +//#define HAS_T4_VGA 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 -#define INVX 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 #define PT8211 1 #else @@ -19,7 +19,11 @@ //#define INVX 1 #define INVY 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 +#define PT8211 1 #endif diff --git a/MCUME_teensy41/teensy20/t4_dsp.cpp b/MCUME_teensy41/teensy20/t4_dsp.cpp new file mode 100644 index 0000000..43301fa --- /dev/null +++ b/MCUME_teensy41/teensy20/t4_dsp.cpp @@ -0,0 +1,1774 @@ +/* + TFT/VGA driver + DMA TFT driver based on C64 ILI9341 dma driver from Frank Bösing, 2017 +*/ + +#include "T4_DSP.h" + +#include +#include + +#include "font8x8.h" + +// TFT constants and variables +#define TFT_LINEARINT 1 +#define LINEARINT_HACK 1 +#define DMA_LINES_PER_BLOCK 64 +#define DMA_NUM_SETTINGS 4 + +#define TFT_SWRESET 0x01 +#define TFT_SLPOUT 0x11 +#define TFT_INVON 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_MADCTL 0x36 +#define TFT_PIXFMT 0x3A +#define TFT_MADCTL_MY 0x80 +#define TFT_MADCTL_MX 0x40 +#define TFT_MADCTL_MV 0x20 +#define TFT_MADCTL_ML 0x10 +#define TFT_MADCTL_RGB 0x00 +#define TFT_MADCTL_BGR 0x08 +#define TFT_MADCTL_MH 0x04 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) +//#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) +//#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) +//#define R16(rgb) ((rgb>>8)&0xf8) +//#define G16(rgb) ((rgb>>3)&0xfc) +//#define B16(rgb) ((rgb<<3)&0xf8) + +// LPSPI4 = SPI0 in Teensy 4.0 +// LPSPI3 = SPI1 in Teensy 4.0 +// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) + +#ifdef TFTSPI1 +#define SPI SPI1 +#define LPSPIP_TDR LPSPI3_TDR +#define LPSPIP_CR LPSPI3_CR +#define LPSPIP_CFGR1 LPSPI3_CFGR1 +#define LPSPIP_TCR LPSPI3_TCR +#define LPSPIP_DER LPSPI3_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX +#else +#define LPSPIP_TDR LPSPI4_TDR +#define LPSPIP_CR LPSPI4_CR +#define LPSPIP_CFGR1 LPSPI4_CFGR1 +#define LPSPIP_TCR LPSPI4_TCR +#define LPSPIP_DER LPSPI4_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX +#endif + +#define SPICLOCK 60000000 +#define SPI_MODE SPI_MODE0 + +// VGA constants and macros +typedef uint8_t vga_pixel; +#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) + +static DMASetting dmasettings[DMA_NUM_SETTINGS]; +static DMAChannel dmatx; +static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K +static volatile uint8_t rstop = 0; +static volatile bool cancelled = false; +static volatile uint8_t curTransfer = 0; +static uint8_t nbTransfer = 0; +static uint16_t * tft_buffer; +static int tft_width; +static int tft_height; +static int tft_stride; + +#define DELAY_MASK 0x80 +PROGMEM static const uint8_t init_commands[] = { + 1+DELAY_MASK, TFT_SWRESET, 150, + 1+DELAY_MASK, TFT_SLPOUT, 255, + 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, + 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, + 1, TFT_INVON, + 1, TFT_DISPON, + 0 +}; + +// VGA constants and variables +// Objective: +// generates VGA signal fully in hardware with as little as possible CPU help + +// Principle: +// QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) +// 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate +// RGB out, combined to create 8bits(/12bits) output. + +// Note: +// - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels +// - experimental resolution: 352x240,352x480 +// - experimental resolution: 512x240,512x480 (not stable) +// - video memory is allocated using malloc in T4 heap +// - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing +// but tried to be compensated by pixel shifting +// - Default is 8bits RRRGGGBB (332) +// But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! +// - Only ok at 600MHz else some disturbances visible + + + +#define TOP_BORDER 40 +#define PIN_HBLANK 15 + +#define PIN_R_B2 33 +#define PIN_R_B1 4 +#define PIN_R_B0 3 +#define PIN_G_B2 2 +#define PIN_G_B1 13 +#define PIN_G_B0 11 +#define PIN_B_B1 12 +#define PIN_B_B0 10 + + +#define DMA_HACK 0x80 + +#define R16(rgb) ((rgb>>8)&0xf8) +#define G16(rgb) ((rgb>>3)&0xfc) +#define B16(rgb) ((rgb<<3)&0xf8) + +// VGA 640x480@60Hz +// Screen refresh rate 60 Hz +// Vertical refresh 31.46875 kHz +// Pixel freq. 25.175 MHz +// +// Visible area 640 25.422045680238 us +// Front porch 16 0.63555114200596 us +// Sync pulse 96 3.8133068520357 us +// Back porch 48 1.9066534260179 us +// Whole line 800 31.777557100298 us + +#define frame_freq 60.0 // Hz +#define line_freq 31.46875 // KHz +#define pix_freq (line_freq*800) // KHz (25.175 MHz) + +// pix_period = 39.7ns +// H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) +#define frontporch_pix 20 //16 +#define backporch_pix 44 //48 + +// Flexio Clock +// PLL3 SW CLOCK (3) => 480 MHz +// PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) +#define FLEXIO_CLK_SEL_PLL3 3 +#define FLEXIO_CLK_SEL_PLL5 2 + +/* Set video PLL */ +// There are /1, /2, /4, /8, /16 post dividers for the Video PLL. +// The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, +// and CCM_ANALOG_MISC2 register sets according to the following equation. +// PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + +// nfact: +// This field controls the PLL loop divider. +// Valid range for DIV_SELECT divider value: 27~54. + +#define POST_DIV_SELECT 2 + +// Full buffer including back/front porch +static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; +static uint32_t dstbuffer __attribute__((aligned(32))); + +// Visible vuffer +static vga_pixel * vga_buffer; +static int vga_width; +static int vga_height; +static int vga_stride; + +static int maxpixperline; +static int left_border; +static int right_border; +static int line_double; +static int pix_shift; +static int ref_div_select; +static int ref_freq_num; +static int ref_freq_denom; +static int ref_pix_shift; +static int combine_shiftreg; + +#ifdef DEBUG +static uint32_t ISRTicks_prev = 0; +volatile uint32_t ISRTicks = 0; +#endif + +uint8_t T4_DSP::_rst; +uint8_t T4_DSP::_cs; +uint8_t T4_DSP::_dc; +uint8_t T4_DSP::_mosi; +uint8_t T4_DSP::_sclk; +uint8_t T4_DSP::_vsync_pin = -1; +DMAChannel T4_DSP::flexio1DMA; +DMAChannel T4_DSP::flexio2DMA; + +static volatile uint32_t VSYNC = 0; +static volatile uint32_t currentLine=0; +#define NOP asm volatile("nop\n\t"); +static gfx_mode_t gfxmode = MODE_UNDEFINED; + + +FASTRUN void T4_DSP::TFT_isr(void) { + dmatx.clearInterrupt(); + curTransfer++; + if (curTransfer >= nbTransfer) { + curTransfer = 0; + if (cancelled) { + dmatx.disable(); + rstop = 1; + } + } + arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); +} + +FASTRUN void T4_DSP::QT3_isr(void) { + TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); + TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); + + cli(); + + // V-PULSE + if (currentLine > 0) { + digitalWrite(_vsync_pin, 1); + VSYNC = 0; + } else { + digitalWrite(_vsync_pin, 0); + VSYNC = 1; + } + + currentLine++; + currentLine = currentLine % 525; + + + uint32_t y = (currentLine - TOP_BORDER) >> line_double; + // Visible area + + if (y >= 0 && y < vga_height) { + // Disable DMAs + //DMA_CERQ = flexio2DMA.channel; + //DMA_CERQ = flexio1DMA.channel; + + // Setup source adress + // Aligned 32 bits copy + unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; + flexio2DMA.TCD->SADDR = p; + if (pix_shift & DMA_HACK) + { + // Unaligned copy + uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; + flexio1DMA.TCD->SADDR = p2; + } + else { + p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 + flexio1DMA.TCD->SADDR = p; + } + + // Enable DMAs + //flexio2DMA.enable(); + //flexio1DMA.enable(); + DMA_SERQ = flexio2DMA.channel; + DMA_SERQ = flexio1DMA.channel; + arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); + } + sei(); + +#ifdef DEBUG + ISRTicks++; +#endif + asm volatile("dsb"); +} + +static void setDmaStruct() { + uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; + uint16_t * fb = (uint16_t*)malloc(remaining); + tft_buffer = fb; + tft_width = TFT_WIDTH; + tft_height = TFT_HEIGHT; + tft_stride = TFT_WIDTH; + uint16_t col=RGBVAL16(0x00,0x00,0x00); + int i=0; + while (remaining > 0) { + int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); + blocks[i] = fb; + for (int j=0;jATTR_DST = 1; + dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); + dmasettings[i].interruptAtCompletion(); + fb += len/2; + remaining -= len; + i++; + } + dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); + nbTransfer = i; +} + +static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 +{ +//if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; + CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE + | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 + | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); + CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; + CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock + const int div_post_pll = 1; // other values: 2,4 + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass +} + +T4_DSP::T4_DSP() +{ + _cs = TFT_CS; + _dc = TFT_DC; + _rst = TFT_RST; + _mosi = TFT_MOSI; + _sclk = TFT_SCLK; + pinMode(_dc, OUTPUT); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, 1); + digitalWrite(_dc, 1); + _vsync_pin = 8; +} + + +void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { + int dx=0; + int dy=0; + digitalWrite(_dc, 0); + SPI.transfer(TFT_CASET); + digitalWrite(_dc, 1); + SPI.transfer16(x1+dx); + digitalWrite(_dc, 1); + SPI.transfer16(x2+dx); + digitalWrite(_dc, 0); + SPI.transfer(TFT_PASET); + digitalWrite(_dc, 1); + SPI.transfer16(y1+dy); + digitalWrite(_dc, 1); + SPI.transfer16(y2+dy); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + return; +} + +void T4_DSP::tft_setup(bool isST) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + // RESET if reset pin defined + if (_rst != 0xff) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + const uint8_t *addr = init_commands; + uint8_t count; + digitalWrite(_cs, 0); + while (count = *addr++) { + uint8_t command = *addr++; + if ( (command == TFT_INVON) && (!isST) ) { + // Skip TFT_INVON for ILI + } + else { + digitalWrite(_dc, 0); // command + SPI.transfer(command); + uint16_t ms = count & DELAY_MASK; + count &= ~DELAY_MASK; + while (--count > 0) { // data + uint8_t data = *addr++; + if ( (command == TFT_MADCTL) && (isST) ) { + data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; + } + digitalWrite(_dc, 1); + SPI.transfer(data); + } + if (ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + digitalWrite(_cs, 1); + SPI.endTransaction(); + delay(2); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + } + } + } + digitalWrite(_cs, 1); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + SPI.endTransaction(); + /* + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_dc, 0); + digitalWrite(_cs, 0); + SPI.transfer(TFT_MADCTL); + digitalWrite(_dc, 1); + SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); + // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); + digitalWrite(_cs, 1); + SPI.endTransaction(); + */ + cancelled = false; +} + +// display VGA image +gfx_error_t T4_DSP::begin(gfx_mode_t mode) +{ + uint32_t flexio_clock_div; + combine_shiftreg = 0; +// int div_select = 49; +// int num = 135; +// int denom = 100; + int div_select = 20; + int num = 9800; + int denom = 10000; + int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; + int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; + set_videoClock(div_select,num,denom,true); + +#ifdef DEBUG + Serial.println(mode); + Serial.println("mode"); +#endif + + switch(mode) + { + case MODE_TFTILI_320x240: +#ifdef DEBUG + Serial.println("TFTILI_320x240"); +#endif + tft_setup(false); + gfxmode = mode; + break; + case MODE_TFTST_320x240: +#ifdef DEBUG + Serial.println("TFTST_320x240"); +#endif + tft_setup(true); + gfxmode = mode; + break; + + case MODE_VGA_320x240: +#ifdef DEBUG + Serial.println("VGA_320x240"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_320x480: +#ifdef DEBUG + Serial.println("VGA_320x480"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_640x240: +#ifdef DEBUG + Serial.println("VGA_640x240"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/pix_freq; + line_double = 1; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_640x480: +#ifdef DEBUG + Serial.println("VGA_640x480"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = (flexio_freq/pix_freq); + line_double = 0; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_512x240: +#ifdef DEBUG + Serial.println("VGA_512x240"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 1; + pix_shift = 0; + break; + + case MODE_VGA_512x480: +#ifdef DEBUG + Serial.println("VGA_512x480"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 0; + pix_shift = 0; + break; + + case MODE_VGA_352x240: +#ifdef DEBUG + Serial.println("VGA_352x240"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_352x480: +#ifdef DEBUG + Serial.println("VGA_352x480"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + } + + if (mode >= MODE_VGA_320x240) + { + if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { + fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); + digitalWrite(_cs, 0); + digitalWrite(_dc, 0); + SPI.transfer(TFT_DISPOFF); + digitalWrite(_cs, 1); + delay(20); + digitalWrite(_cs, 0); + digitalWrite(_cs, 1); + } + gfxmode = mode; + + maxpixperline = vga_stride; + // Save param for tweek adjustment + ref_div_select = div_select; + ref_freq_num = num; + ref_freq_denom = denom; + ref_pix_shift = pix_shift; + +#ifdef DEBUG + Serial.println("frequency"); + Serial.println(flexio_freq); + Serial.println("div"); + Serial.println(flexio_freq/pix_freq); +#endif + + pinMode(_vsync_pin, OUTPUT); + pinMode(PIN_HBLANK, OUTPUT); + + /* Basic pin setup FlexIO1 */ + pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 + pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 + pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 + pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 + /* Basic pin setup FlexIO2 */ + pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 + pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 + pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 + pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 + + /* High speed and drive strength configuration */ + *(portControlRegister(PIN_G_B2)) = 0xFF; + *(portControlRegister(PIN_R_B0)) = 0xFF; + *(portControlRegister(PIN_R_B1)) = 0xFF; + *(portControlRegister(PIN_R_B2)) = 0xFF; + *(portControlRegister(PIN_B_B0)) = 0xFF; + *(portControlRegister(PIN_B_B1)) = 0xFF; + *(portControlRegister(PIN_G_B0)) = 0xFF; + *(portControlRegister(PIN_G_B1)) = 0xFF; + + /* Set clock for FlexIO1 and FlexIO2 */ + CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) + | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); + CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) + | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); + + + /* Set up pin mux FlexIO1 */ + *(portConfigRegister(PIN_G_B2)) = 0x14; + *(portConfigRegister(PIN_R_B0)) = 0x14; + *(portConfigRegister(PIN_R_B1)) = 0x14; + *(portConfigRegister(PIN_R_B2)) = 0x14; + /* Set up pin mux FlexIO2 */ + *(portConfigRegister(PIN_B_B0)) = 0x14; + *(portConfigRegister(PIN_B_B1)) = 0x14; + *(portConfigRegister(PIN_G_B0)) = 0x14; + *(portConfigRegister(PIN_G_B1)) = 0x14; + + /* Enable the clock */ + CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + /* Enable the FlexIO with fast access */ + FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + + uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; + uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; + + /* Shifter 0 registers for FlexIO2 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 + inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter + stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled + startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable + timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 + timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock + pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output + pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity + shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode + /* Shifter 0 registers for FlexIO1 */ + FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + /* Shifter 0 registers for FlexIO1 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 + FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + if (combine_shiftreg) { + pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled + FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + } + /* Timer 0 registers for FlexIO2 */ + timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset + timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output + timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset + timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare + timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert + stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled + startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled + if (combine_shiftreg) { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag + } + else { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag + } + triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low + triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected + pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled + //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 + //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high + timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode + // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) + + int shifts_per_transfer; + if (combine_shiftreg) { + shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 + } + else { + shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 + } + FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); + /* Timer 0 registers for FlexIO1 */ + FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); +#ifdef DEBUG + Serial.println("FlexIO setup complete"); +#endif + + /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ + if (combine_shiftreg) { + FLEXIO2_SHIFTSDEN |= (1<<1); + FLEXIO1_SHIFTSDEN |= (1<<1); + } + else { + FLEXIO2_SHIFTSDEN |= (1<<0); + FLEXIO1_SHIFTSDEN |= (1<<0); + } + /* Disable DMA channel so it doesn't start transferring yet */ + flexio1DMA.disable(); + flexio2DMA.disable(); + /* Set up DMA channel to use Shifter 0 trigger */ + flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); + flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); + + + if (combine_shiftreg) { + flexio2DMA.TCD->NBYTES = 8; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 8; + flexio2DMA.TCD->CITER = maxpixperline / 8; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + flexio1DMA.TCD->NBYTES = 8; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 8; + flexio1DMA.TCD->CITER = maxpixperline / 8; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Setup DMA2 Flexio2 copy + flexio2DMA.TCD->NBYTES = 4; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 4; + flexio2DMA.TCD->CITER = maxpixperline / 4; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + // Setup DMA1 Flexio1 copy + // Use pixel shift to avoid color smearing? + if (pix_shift & DMA_HACK) + { + if (pix_shift & 0x3 == 0) { + // Aligned 32 bits copy (32bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Unaligned (source) 32 bits copy (8bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 1; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion + } + } + else + { + // Aligned 32 bits copy + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + } + +#ifdef DEBUG + Serial.println("DMA setup complete"); +#endif + + // enable clocks for QTIMER3: generates the 15KHz for hsync + // Pulse: + // low : 3.8133 us => 569x6.7ns + // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) + // (OLD TEST) + // (4us low, 28us high => 32us) + // (597x6.7ns for 4us) + // (4179x6.7ns for 28us) + CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 + //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 + + #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz + #define MARGIN_D 1000 + + TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer + // Invert output pin as we want the interupt on rising edge + TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) + TMR3_CNTR3 = 0; + TMR3_LOAD3 = 0; + + /* Inverted timings */ + unsigned long long cpu_freq = F_CPU; + unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; + int rate2 = rate; + + int substract = 1; + if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { + substract=5; + rate2=1652; + } + + #ifdef DEBUG + Serial.print("MARGIN_N is: "); + Serial.println(rate2, DEC); + Serial.print("SUBSTRACT is: "); + Serial.println(substract, DEC); +#endif + TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; + TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; + /* + TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; + */ + TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on + TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), + // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) + //configure Teensy pin Compare output + IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 + attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function + NVIC_ENABLE_IRQ(IRQ_QTIMER3); +#ifdef DEBUG + Serial.println("QTIMER3 setup complete"); + Serial.print("V-PIN is "); + Serial.println(_vsync_pin); +#endif + + /* initialize gfx buffer */ + if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift + if (gfxbuffer == NULL) return(GFX_ERROR); +#ifdef DEBUG + Serial.println("Memory allocated"); +#endif + + memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); + vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; +#ifdef DEBUG + Serial.println(vga_stride); + Serial.println(vga_height); + Serial.println("Screen cleared"); +#endif + } + + return(GFX_OK); +} + +gfx_mode_t T4_DSP::getMode(void) +{ + return gfxmode; +} + +void T4_DSP::startRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + curTransfer = 0; + rstop = 0; + //dmatx.begin(true); + dmatx.attachInterrupt(TFT_isr); + setDmaStruct(); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + + digitalWrite(_cs, HIGH); + SPI.begin(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + + LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: + LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX + LPSPIP_TCR = 15; // Framesize 16 Bits + //LPSPIP_FCR = 0; // Fifo Watermark + LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable + LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: + dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); + + dmatx = dmasettings[0]; + digitalWrite(_cs, 0); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + dmatx.enable(); + } +} + + +void T4_DSP::stopRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + rstop = 1; + unsigned long m = millis(); + cancelled = true; + while (!rstop) { + if ((millis() - m) > 100) break; + delay(10); + asm volatile("wfi"); + }; + rstop = 0; + delay(50); + cancelled = false; + dmatx.detachInterrupt(); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + SPI.end(); +#ifdef ST7789 +// begin(gfxmode); +#endif + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + } +} + +int T4_DSP::get_frame_buffer_size(int *width, int *height) { + if (gfxmode < MODE_VGA_320x240) { + if (width != nullptr) *width = tft_width; + if (height != nullptr) *height = tft_height; + return tft_stride; + } + else { + if (width != nullptr) *width = vga_width; + if (height != nullptr) *height = vga_height; + return vga_stride; + } +} + +void T4_DSP::waitSync() +{ + if (gfxmode >= MODE_VGA_320x240) { + while (VSYNC == 0) {}; + } +} + +void T4_DSP::waitLine(int line) +{ + if (gfxmode >= MODE_VGA_320x240) { + while (currentLine != line) {}; + } +} + +/*********************************************************************************************** + No DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreenNoDma(uint16_t color) { + if (gfxmode < MODE_VGA_320x240) { + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + int i,j; + for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(arx, ary, arx+arw-1, ary+arh-1); + bitmap = bitmap + bmp_offy*w + bmp_offx; + for (int row=0;row> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + bits = *charpt++; + //digitalWrite(_dc, 1); + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + x +=8; + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + else { + drawText(x, y, text, fgcolor, bgcolor, doublesize); + } +} + + +/*********************************************************************************************** + DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreen(uint16_t color) { + int i,j; + if (gfxmode < MODE_VGA_320x240) { + for (j=0; j> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + dst=&tft_buffer[l*tft_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + x +=8; + } + } + else { + vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); + vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); + vga_pixel * dst; + while ((c = *text++)) { + const unsigned char * charpt=&font8x8[c][0]; + int l=y; + for (int i=0;i<8;i++) + { + unsigned char bits; + if (doublesize) { + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + x +=8; + } + } +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { + drawSprite(x,y,bitmap, 0,0,0,0); +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) +{ + int bmp_offx = 0; + int bmp_offy = 0; + uint16_t *bmp_ptr; + int w =*bitmap++; + int h = *bitmap++; + if ( (arw == 0) || (arh == 0) ) { + // no crop window + arx = x; + ary = y; + arw = w; + arh = h; + } + else { + if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + int l=ary; + bitmap = bitmap + bmp_offy*w + bmp_offx; + + if (gfxmode < MODE_VGA_320x240) { + for (int row=0;row tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]; + pos +=step; + } + #endif + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i 2) ) y += (tft_height-height)/2; + uint16_t * dst=&tft_buffer[y*tft_stride]; + if (width > tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]]; + pos +=step; + } +#endif + } + else if ((width*2) == tft_width) { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]]; + *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i tft_width) { + int step = ((width << 8)/tft_width); + int pos = 0; + for (int i=0; i> 8]]; + pos +=step; + } + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = pix; + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i +#include +#endif + +#include "platform_config.h" +#include "iopins.h" + + + +#ifndef TFT_WIDTH +#define TFT_WIDTH 320 +#endif +#define TFT_REALWIDTH 320 + +#ifndef TFT_HEIGHT +#define TFT_HEIGHT 240 +#endif +#define TFT_REALHEIGHT 240 + + +typedef enum gfx_mode_t +{ + MODE_UNDEFINED = 0, + MODE_TFTILI_320x240 = 1, + MODE_TFTST_320x240 = 2, + MODE_VGA_320x240 = 3, + MODE_VGA_320x480 = 4, + MODE_VGA_352x240 = 5, + MODE_VGA_352x480 = 6, + MODE_VGA_512x240 = 7, + MODE_VGA_512x480 = 8, + MODE_VGA_640x240 = 9, + MODE_VGA_640x480 = 10 +} gfx_mode_t; + +typedef enum gfx_error_t +{ + GFX_OK = 0, + GFX_ERROR = -1 +} gfx_error_t; + + +#ifdef __cplusplus + +class T4_DSP +{ + public: + T4_DSP(); + + gfx_error_t begin(gfx_mode_t mode); + gfx_mode_t getMode(void); + void startRefresh(void); + void stopRefresh(); + + int get_frame_buffer_size(int *width, int *height); + void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); + + // wait next Vsync + void waitSync(); + void waitLine(int line); + + // NoDMA functions + void fillScreenNoDma(uint16_t color); + void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + // DMA functions + void fillScreen(uint16_t color); + void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + void writeLine(int width, int height, int y, uint16_t *buf); + void writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + void writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16); + void writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + + protected: + static uint8_t _rst, _cs, _dc; + static uint8_t _mosi, _sclk; + static uint8_t _vsync_pin; + static DMAChannel flexio1DMA; + static DMAChannel flexio2DMA; + void tft_setup(bool isST); + static void TFT_isr(void); + static void QT3_isr(void); +}; + +#endif +#endif diff --git a/MCUME_teensy41/teensy20/teensy20.ino b/MCUME_teensy41/teensy20/teensy20.ino index 612b2ea..88bcedb 100644 --- a/MCUME_teensy41/teensy20/teensy20.ino +++ b/MCUME_teensy41/teensy20/teensy20.ino @@ -3,133 +3,16 @@ extern "C" { #include "iopins.h" } -#include "v20.h" - -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -TFT_T_DMA tft; -#else -#include "tft_t_dma.h" -TFT_T_DMA tft = TFT_T_DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, TFT_TOUCH_CS, TFT_TOUCH_INT); -#endif - -bool vgaMode = false; - -static unsigned char palette8[PALETTE_SIZE]; -static unsigned short palette16[PALETTE_SIZE]; -static IntervalTimer myTimer; -volatile boolean vbl=true; -static int skip=0; -static elapsedMicros tius; - -static void vblCount() { - if (vbl) { - vbl = false; - } else { - vbl = true; - } -} - -void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) -{ - if (index>8, - 320 & 0xFF, // YEND = 320 - ST7735_INVON , DELAY, // 7: hack - 10, - ST7735_NORON , DELAY, // 8: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 9: Main screen turn on, no args, w/delay - 255 -#endif -}; - -static void dmaInterrupt() { - dmatx.clearInterrupt(); - curTransfer++; - if (curTransfer >= nbTransfer) { - curTransfer = 0; - if (cancelled) { - dmatx.disable(); - rstop = 1; - } - } - arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2); -} - -static void setDmaStruct() { - uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; - int i=0; - uint16_t col=RGBVAL16(0x00,0x00,0x00);; - while (remaining > 0) { - uint16_t * fb = blocks[i]; - int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining); -#ifdef TFT_DEBUG - Serial.println((unsigned long)blocks[i]); - Serial.println(remaining); -#endif - switch (i) { - case 0: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb0[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0x00); -#endif - break; - case 1: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb1[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0xff); -#endif - break; - case 2: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb2[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0x00,0xff); -#endif - break; - case 3: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb3[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0xff,0x00,0xff); -#endif - break; - } - blocks[i] = fb; - if (blocks[i] == 0) { - Serial.print("ILI9341 allocaltion failed for block "); - Serial.println(i); - delay(10000); - } - - for (int j=0;jATTR_DST = 1; - dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); - dmasettings[i].interruptAtCompletion(); - remaining -= len; - i++; - } - dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); - nbTransfer = i; -#ifdef TFT_DEBUG - Serial.println(nbTransfer); -#endif -} - - -TFT_T_DMA::TFT_T_DMA(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso, uint8_t touch_cs, uint8_t touch_irq) -{ - _cs = cs; - _dc = dc; - _rst = rst; - _mosi = mosi; - _sclk = sclk; - _miso = miso; - pinMode(_dc, OUTPUT); - pinMode(_cs, OUTPUT); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); - if ( (touch_cs != 255) && (touch_irq != 255) ) { - _touch_irq = touch_irq; - _touch_cs = touch_cs; - pinMode(_touch_cs, OUTPUT); - pinMode(touch_irq, INPUT_PULLUP); - digitalWrite(_touch_cs, 1); - } -} - - -void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { - int dx=0; - int dy=0; -#ifdef ST7789 - if (TFT_REALWIDTH == TFT_REALHEIGHT) - { -#ifdef ROTATE_SCREEN - if (!flipped) { - dy += 80; - } -#else - if (flipped) { - dx += 80; - } -#endif - } -#endif - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - SPI.transfer16(x1+dx); - digitalWrite(_dc, 1); - SPI.transfer16(x2+dx); - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - digitalWrite(_dc, 1); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - return; - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - - SPI.transfer16(x1+dx); - SPI.transfer16(x2+dx); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - -void TFT_T_DMA::begin(void) { - SPI.setMOSI(_mosi); - SPI.setMISO(_miso); - SPI.setSCK(_sclk); - SPI.begin(); - - // Initialize display - if (_rst != 0xff) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - const uint8_t *addr = init_commands; - digitalWrite(_cs, 0); -#ifdef ILI9341 - while (1) { - uint8_t count = *addr++; - if (count-- == 0) break; - - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - - while (count-- > 0) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - } - - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(ILI9341_DISPON); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); -#endif -#ifdef ST7789 - uint8_t numCommands, numArgs; - uint16_t ms; - numCommands = *addr++; // Number of commands to follow - while(numCommands--) { // For each command... - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - numArgs = *addr++; // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs > 1) { // For each argument... - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - numArgs--; - } - - if (numArgs) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - if(ms) { - ms = *addr++; // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - digitalWrite(_cs, 1); - SPI.endTransaction(); - delay(ms); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - } - } - digitalWrite(_cs, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - SPI.endTransaction(); - - cancelled = false; - -#ifdef FLIP_SCREEN - flipscreen(true); -#else - flipscreen(false); -#endif -#ifdef ST7789 - if (TFT_REALWIDTH != TFT_REALHEIGHT) - { - flipscreen(true); - } -#endif -}; - - - -void TFT_T_DMA::flipscreen(bool flip) -{ - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(TFT_MADCTL); - digitalWrite(_dc, 1); - if (flip) { - flipped=true; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB); -#endif -#endif - } - else { - flipped=false; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB); -#endif -#endif - } - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - -boolean TFT_T_DMA::isflipped(void) -{ - return(flipped); -} - - -#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) - - -void TFT_T_DMA::startDMA(void) { - curTransfer = 0; - rstop = 0; - //dmatx.begin(true); - dmatx.attachInterrupt(dmaInterrupt); - setDmaStruct(); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - - digitalWrite(_cs, HIGH); - SPI.begin(); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); - - - LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: - LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX - LPSPIP_TCR = 15; // Framesize 16 Bits - //LPSPIP_FCR = 0; // Fifo Watermark - LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable - LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: - dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); - - dmatx = dmasettings[0]; - digitalWrite(_cs, 0); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - dmatx.enable(); -} - - -void TFT_T_DMA::stopDMA(void) { - rstop = 0; - wait(); - delay(50); - cancelled = false; - dmatx.detachInterrupt(); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - SPI.end(); -#ifdef ST7789 - begin(); -#endif -#ifdef ILI9341 - SPI.begin(); - digitalWrite(_cs, 0); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - SPI.endTransaction(); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); -} - -void TFT_T_DMA::wait(void) { - rstop = 1; - unsigned long m = millis(); - cancelled = true; - while (!rstop) { - if ((millis() - m) > 100) break; - delay(10); - asm volatile("wfi"); - }; - rstop = 0; -} - -int TFT_T_DMA::get_frame_buffer_size(int *width, int *height){ - if (width != nullptr) *width = TFT_REALWIDTH; - if (height != nullptr) *height = TFT_REALHEIGHT; - return TFT_REALWIDTH; -} - - -/*********************************************************************************************** - Touch functions - ***********************************************************************************************/ -/* Code based on ... - * - * @file XPT2046.cpp - * @date 19.02.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the XPT2046 driver for Arduino. - */ - -#define ADC_MAX 0x0fff - -void TFT_T_DMA::enableTouchIrq() -{ - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 }; - SPI.transfer((void*)&buf[0],3); - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); -} - -//Default callibration for non flipped -#define TX_MIN 30 -#define TY_MIN 20 -#define TX_MAX 300 -#define TY_MAX 220 - -//Default callibration for flipped -#define TFX_MIN 20 -#define TFY_MIN 25 -#define TFX_MAX 288 -#define TFY_MAX 221 - -static uint16_t txMin; -static uint16_t tyMin; -static uint16_t txMax; -static uint16_t tyMax; - - -void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { - if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) { - txMin = xMin; - tyMin = yMin; - txMax = xMax; - tyMax = yMax; - } - else { - if (flipped) { - txMin = TFX_MIN; - tyMin = TFY_MIN; - txMax = TFX_MAX; - tyMax = TFY_MAX; - } - else { - txMin = TX_MIN; - tyMin = TY_MIN; - txMax = TX_MAX; - tyMax = TY_MAX; - } - } -} - - -void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - if ( TOUCH_ENABLED() ) { - uint16_t x = 0; - uint16_t y = 0; - uint16_t z1 = 0; - uint16_t z2 = 0; - uint8_t i = 0; - int16_t xraw=0, yraw=0; - - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - - for(; i < 15; i++) { - // SPI requirer 32bit aliment - uint8_t buf[12] = { - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00 - }; - SPI.transfer(&buf[0], &buf[0], 12); - y += (buf[1] << 8 | buf[2])>>3; - x += (buf[4] << 8 | buf[5])>>3; - z1 += (buf[7] << 8 | buf[8])>>3; - z2 += (buf[10] << 8 | buf[11])>>3; - } - enableTouchIrq(); - - if(i == 0) { - *oX = 0; - *oY = 0; - *oZ = 0; - } - else { - x /= i; - y /= i; - z1 /= i; - z2 /= i; - } - - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); - int z = z1 + ADC_MAX - z2; - if (flipped) { - xraw = x; - yraw = y; - } else { - xraw = ADC_MAX - x; - yraw = ADC_MAX - y; - } - xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1); - yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1); - - *oX = xraw; - *oY = yraw; - *oZ = z; - } - else - { - *oX = 0; - *oY = 0; - *oZ = 0; - } -} - -void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - readRaw(oX,oY,oZ); - // callibrate ... - if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin); - if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin); - //Serial.print(*oX); - //Serial.print(" "); - //Serial.println(*oY); -} - - -/*********************************************************************************************** - No DMA functions - ***********************************************************************************************/ -void TFT_T_DMA::fillScreenNoDma(uint16_t color) { - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - int i,j; - for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(arx, ary, arx+arw-1, ary+arh-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - bits = *charpt++; - //digitalWrite(_dc, 1); - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - x +=8; -#ifdef ILI9341 - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); -#endif - digitalWrite(_cs, 1); - SPI.endTransaction(); - } - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - - - -/*********************************************************************************************** - DMA functions - ***********************************************************************************************/ -uint16_t * TFT_T_DMA::getLineBuffer(int j) -{ - uint16_t * block=blocks[j>>6]; - return(&block[(j&0x3F)*TFT_REALWIDTH]); -} - -void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) { - uint8_t *buffer=buf; - uint8_t *src; - - int i,j,y=0; - if (width*2 <= TFT_REALWIDTH) { - for (j=0; j>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH]; - for (i=0; i>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x]; - for (i=0; i>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - block=blocks[l>>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt++; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - x +=8; - } -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { - drawSprite(x,y,bitmap, 0,0,0,0); -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) -{ - int bmp_offx = 0; - int bmp_offy = 0; - uint16_t *bmp_ptr; - - int w =*bitmap++; - int h = *bitmap++; - - - if ( (arw == 0) || (arh == 0) ) { - // no crop window - arx = x; - ary = y; - arw = w; - arh = h; - } - else { - if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - int l=ary; - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx]; - bmp_ptr = (uint16_t*)bitmap; - for (int col=0;col -#include -#include -#endif - -#include "tft_t_dma_config.h" - -#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) -#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define R16(rgb) ((rgb>>8)&0xf8) -#define G16(rgb) ((rgb>>3)&0xfc) -#define B16(rgb) ((rgb<<3)&0xf8) - -#define PAL_COLOR_MASK 0xff - -#ifdef LOHRES -#define TFT_WIDTH 240 -#define TFT_REALWIDTH 240 -#else -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 -#endif -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - -//#define WIDTH 272 -//#define HEIGHT 228 - -#define LINES_PER_BLOCK 64 -#define NR_OF_BLOCK 4 -#define SCREEN_DMA_NUM_SETTINGS NR_OF_BLOCK - - -#ifdef ILI9341 - -#define ILI9341_NOP 0x00 -#define ILI9341_SWRESET 0x01 -#define ILI9341_RDDID 0x04 -#define ILI9341_RDDST 0x09 - -#define ILI9341_SLPIN 0x10 -#define ILI9341_SLPOUT 0x11 -#define ILI9341_PTLON 0x12 -#define ILI9341_NORON 0x13 - -#define ILI9341_RDMODE 0x0A -#define ILI9341_RDMADCTL 0x0B -#define ILI9341_RDPIXFMT 0x0C -#define ILI9341_RDIMGFMT 0x0D -#define ILI9341_RDSELFDIAG 0x0F - -#define ILI9341_INVOFF 0x20 -#define ILI9341_INVON 0x21 -#define ILI9341_GAMMASET 0x26 -#define ILI9341_DISPOFF 0x28 -#define ILI9341_DISPON 0x29 - -#define ILI9341_CASET 0x2A -#define ILI9341_PASET 0x2B -#define ILI9341_RAMWR 0x2C -#define ILI9341_RAMRD 0x2E - -#define ILI9341_PTLAR 0x30 -#define ILI9341_MADCTL 0x36 -#define ILI9341_VSCRSADD 0x37 -#define ILI9341_PIXFMT 0x3A - -#define ILI9341_FRMCTR1 0xB1 -#define ILI9341_FRMCTR2 0xB2 -#define ILI9341_FRMCTR3 0xB3 -#define ILI9341_INVCTR 0xB4 -#define ILI9341_DFUNCTR 0xB6 - -#define ILI9341_PWCTR1 0xC0 -#define ILI9341_PWCTR2 0xC1 -#define ILI9341_PWCTR3 0xC2 -#define ILI9341_PWCTR4 0xC3 -#define ILI9341_PWCTR5 0xC4 -#define ILI9341_VMCTR1 0xC5 -#define ILI9341_VMCTR2 0xC7 - -#define ILI9341_RDID1 0xDA -#define ILI9341_RDID2 0xDB -#define ILI9341_RDID3 0xDC -#define ILI9341_RDID4 0xDD - -#define ILI9341_GMCTRP1 0xE0 -#define ILI9341_GMCTRN1 0xE1 - -#define ILI9341_MADCTL_MY 0x80 -#define ILI9341_MADCTL_MX 0x40 -#define ILI9341_MADCTL_MV 0x20 -#define ILI9341_MADCTL_ML 0x10 -#define ILI9341_MADCTL_RGB 0x00 -#define ILI9341_MADCTL_BGR 0x08 -#define ILI9341_MADCTL_MH 0x04 - -#define TFT_CASET ILI9341_CASET -#define TFT_PASET ILI9341_PASET -#define TFT_RAMWR ILI9341_RAMWR -#define TFT_MADCTL ILI9341_MADCTL - -#endif - - -#ifdef ST7789 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_RGB 0x00 -#define ST77XX_MADCTL_BGR 0x08 -#define ST77XX_MADCTL_MH 0x04 - -#define TFT_CASET ST7735_CASET -#define TFT_PASET ST7735_RASET -#define TFT_RAMWR ST7735_RAMWR -#define TFT_MADCTL ST7735_MADCTL - -#endif - - - -#ifdef __cplusplus - -class TFT_T_DMA -{ - public: - TFT_T_DMA(uint8_t _CS, uint8_t _DC, uint8_t _RST = 255, uint8_t _MOSI=11, uint8_t _SCLK=13, uint8_t _MISO=12, uint8_t touch_cs=38, uint8_t touch_irq=37); - - void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); - void begin(void); - void flipscreen(bool flip); - boolean isflipped(void); - void startDMA(void); - void stopDMA(); - int get_frame_buffer_size(int *width, int *height); - - // Touch screen functions - #define TOUCH_ENABLED() ((_touch_cs != 255) && (_touch_irq != 255)) - bool isTouching(void) { return ((!TOUCH_ENABLED())?false:(digitalRead(_touch_irq) == LOW)); } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax); - - // NoDMA functions - void writeScreenNoDma(const uint16_t *pcolors); - void fillScreenNoDma(uint16_t color); - void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - // DMA functions - uint16_t * getLineBuffer(int j); - void writeScreen(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int y, uint16_t *buf); - void fillScreen(uint16_t color); - void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - protected: - uint8_t _rst, _cs, _dc; - uint8_t _miso, _mosi, _sclk; - uint8_t _touch_irq=255, _touch_cs=255; - bool flipped=false; - - void wait(void); - void enableTouchIrq(); -}; - -#endif -#endif - - diff --git a/MCUME_teensy41/teensy20/tft_t_dma_config.h b/MCUME_teensy41/teensy20/tft_t_dma_config.h deleted file mode 100644 index 354cf74..0000000 --- a/MCUME_teensy41/teensy20/tft_t_dma_config.h +++ /dev/null @@ -1,14 +0,0 @@ -#include "platform_config.h" - -//#define ST7789 1 -//#define ILI9341 1 - -#define TFT_LINEARINT 1 -#define LINEARINT_HACK 1 - -//#define FLIP_SCREEN 1 -//#define TFT_DEBUG 1 -#if defined(__IMXRT1052__) || defined(__IMXRT1062__) -//#define TFT_STATICFB 1 -#endif - diff --git a/MCUME_teensy41/teensy20/vga_t_dma.h b/MCUME_teensy41/teensy20/vga_t_dma.h deleted file mode 100644 index 81a986b..0000000 --- a/MCUME_teensy41/teensy20/vga_t_dma.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - Wrapping class to extend VGA_T4 to TFT_T_DMA -*/ - -#ifndef _VGA_T_DMAH_ -#define _VGA_T_DMAH_ - -#ifdef __cplusplus -#include -#endif - - -#define RGBVAL16(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) - - - - -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 - -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - - - -#ifdef __cplusplus - -class TFT_T_DMA: public VGA_T4 -{ - public: - // Fake touch screen functions - bool isTouching(void) { return false; } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { } - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { }; - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { } - - // fake DMA functions - void startDMA(void) { }; - void stopDMA(void) { }; - - // fake no DMA functions - void writeScreenNoDma(const vga_pixel *pcolors) { writeScreen(pcolors); } - void fillScreenNoDma(vga_pixel color) { clear(color); } - void drawTextNoDma(int16_t x, int16_t y, const char * text, vga_pixel fgcolor, vga_pixel bgcolor, bool doublesize) { drawText(x,y,text,fgcolor,bgcolor,doublesize); } - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, vga_pixel color) { drawRect(x, y, w, h, color); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap) { drawSprite(x, y, bitmap); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh) { drawSprite(x, y, bitmap, croparx, cropary, croparw, croparh); } -}; - - -#endif -#endif diff --git a/MCUME_teensy41/teensy20/v20.cpp b/MCUME_teensy41/teensy20/wrapemu.cpp similarity index 83% rename from MCUME_teensy41/teensy20/v20.cpp rename to MCUME_teensy41/teensy20/wrapemu.cpp index bf22842..62d0ba2 100644 --- a/MCUME_teensy41/teensy20/v20.cpp +++ b/MCUME_teensy41/teensy20/wrapemu.cpp @@ -176,25 +176,24 @@ __ const uint32_t ascii2scan[] = { //0 1 2 3 4 5 6 7 8 9 A B C D E F - 0,0,0,0,0,0,0,0,0,0,0xfd7f,0,0,0,0,0, // return - // 31:RUNSTOP - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xf7fe, + 0,0,0,0,0,0,0,0,0,0,0xfd7f,0,0,0xfd7f,0,0, // return + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xf7fe, //31:RUNSTOP //sp ! " # $ % & ' ( ) * + , - . / - 0xeffe ,0x1fefe,0x17ffe,0x1fe02,0x17ffd,0x1fefb,0x17ffb,0x1fef7,0x17ff7,0x1feef,0xfdbf ,0xfedf ,0xf7df ,0x7fDf ,0xefdf ,0xf7bf, + 0xeffe ,0x1fefe,0x17ffe,0x1fefd,0x17ffd,0x1fefb,0xfebf,0x1fef7,0x17ff7,0x1feef,0xfdbf ,0xfedf ,0xf7df ,0x7fDf ,0xefdf ,0xf7bf, //0 1 2 3 4 5 6 7 8 9 : ; < = > ? 0x7fef ,0xfefe ,0x7ffe ,0xfefd ,0x7ffd ,0xfefb ,0x7ffb ,0xfef7 ,0x7ff7 ,0xfeef ,0xdfdf ,0xfbbf ,0x1f7df,0xdfbf ,0x1efdf,0x1f7bf, //@ A B C D E F G H I J K L M N O 0xbfdf ,0xfbfd ,0xeff7 ,0xeffb ,0xfbfb ,0xbffd ,0xdffb ,0xfbf7 ,0xdff7 ,0xfdef ,0xfbef ,0xdfef ,0xfbdf ,0xefef ,0xf7ef ,0xbfef, //P Q R S T U V W X Y Z [ \ ] ^ _ 0xfddf ,0xbffe ,0xfdfb ,0xdffd ,0xbffb ,0xbff7 ,0xf7f7 ,0xfdfd ,0xf7fb ,0xfdf7 ,0xeffd ,0x1dfdf,0xffff ,0x1fbbf,0 ,0, - //' a c c d e f g h i j k l m n o + //' a b c d e f g h i j k l m n o 0 ,0xfbfd ,0xeff7 ,0xeffb ,0xfbfb ,0xbffd ,0xdffb ,0xfbf7 ,0xdff7 ,0xfdef ,0xfbef ,0xdfef ,0xfbdf ,0xefef ,0xf7ef ,0xbfef, - //p q r s t u v w x y z { | } ~ DEL - 0xfddf ,0xbffe ,0xfdfb ,0xdffd ,0xbffb ,0xbff7 ,0xf7f7 ,0xfdfd ,0xf7fb ,0xfdf7 ,0xeffd ,0, 0 , 0, 0xfe7f ,0, - // 129:f1 f2 f3 f4 f5 f6 f7 f8 - 0,0xef7f,0x1ef7f,0xdf7f,0x1df7f,0xbf7f,0x1bf7f,0x7f7f,0x17f7f,0,0,0,0,0,0,0, // 128-143 - // 150:right left down up 157:left - 0,0,0,0,0,0, 0xfb7f,0x1fb7f,0xf77f,0x1f77f,0,0,0,0,0,0 // 144-159 + //p q r s t u v w x y z { | } ~ DEL + 0xfddf ,0xbffe ,0xfdfb ,0xdffd ,0xbffb ,0xbff7 ,0xf7f7 ,0xfdfd ,0xf7fb ,0xfdf7 ,0xeffd ,0, 0 , 0, 0xfe7f ,0, + // f1 f2 f3 f4 f5 f6 f7 f8 + 0, 0xef7f, 0x1ef7f, 0xdf7f,0x1df7f,0xbf7f, 0x1bf7f,0x7f7f,0x17f7f,0,0,0,0,0,0,0, // 128-143 + // 150:right left down up + 0,0,0,0,0,0, 0xfb7f, 0x1fb7f, 0xf77f, 0x1f77f,0,0,0,0,0,0 // 144-159 }; @@ -374,7 +373,9 @@ void v20_Step(void) int hk=ihk; if (iusbhk) hk = iusbhk; +#ifdef TEECOMPUTER if (hk) { + Serial.println(hk); int scan = ascii2scan[hk]; if (scan & 0x10000) mos6522.setShiftPressed(true); else mos6522.setShiftPressed(false); @@ -384,12 +385,13 @@ void v20_Step(void) mos6522.setShiftPressed(false); mos6522.setKeyPressed(0); } - +#endif int k=ik; #ifdef TEECOMPUTER // Ignore joypad if shift/fn is pressed!!! - if ( !(k & MASK_KEY_USER1) && !(k & MASK_KEY_USER2) ) + //if ( !(k & MASK_KEY_USER1) && !(k & MASK_KEY_USER2) ) + if ( hk == 0 ) #endif { if ( !(pik & MASK_JOY2_BTN) && (k & MASK_JOY2_BTN) ) { @@ -411,17 +413,49 @@ void v20_Step(void) mos6522.setJoyStickPressed(MOS6522::Vic20JoyStickButton::Down, false); } if ( !(pik & MASK_JOY2_RIGHT) && (k & MASK_JOY2_RIGHT) ) { - mos6522.setJoyStickPressed(MOS6522::Vic20JoyStickButton::Left, true); - } - else if ( (pik & MASK_JOY2_RIGHT) && !(k & MASK_JOY2_RIGHT) ) { - mos6522.setJoyStickPressed(MOS6522::Vic20JoyStickButton::Left, false); - } - if ( !(pik & MASK_JOY2_LEFT) && (k & MASK_JOY2_LEFT) ) { mos6522.setJoyStickPressed(MOS6522::Vic20JoyStickButton::Right, true); } - else if ( (pik & MASK_JOY2_LEFT) && !(k & MASK_JOY2_LEFT) ) { + else if ( (pik & MASK_JOY2_RIGHT) && !(k & MASK_JOY2_RIGHT) ) { mos6522.setJoyStickPressed(MOS6522::Vic20JoyStickButton::Right, false); } + if ( !(pik & MASK_JOY2_LEFT) && (k & MASK_JOY2_LEFT) ) { + mos6522.setJoyStickPressed(MOS6522::Vic20JoyStickButton::Left, true); + } + else if ( (pik & MASK_JOY2_LEFT) && !(k & MASK_JOY2_LEFT) ) { + mos6522.setJoyStickPressed(MOS6522::Vic20JoyStickButton::Left, false); + } + + if ( !(pik & MASK_JOY1_BTN) && (k & MASK_JOY1_BTN) ) { + mos6522.setJoyStickPressed(MOS6522::Vic20JoyStickButton::Fire, true); + } + else if ( (pik & MASK_JOY1_BTN) && !(k & MASK_JOY1_BTN) ) { + mos6522.setJoyStickPressed(MOS6522::Vic20JoyStickButton::Fire, false); + } + if ( !(pik & MASK_JOY1_UP) && (k & MASK_JOY1_UP) ) { + mos6522.setJoyStickPressed(MOS6522::Vic20JoyStickButton::Up, true); + } + else if ( (pik & MASK_JOY1_UP) && !(k & MASK_JOY1_UP) ) { + mos6522.setJoyStickPressed(MOS6522::Vic20JoyStickButton::Up, false); + } + if ( !(pik & MASK_JOY1_DOWN) && (k & MASK_JOY1_DOWN) ) { + mos6522.setJoyStickPressed(MOS6522::Vic20JoyStickButton::Down, true); + } + else if ( (pik & MASK_JOY1_DOWN) && !(k & MASK_JOY1_DOWN) ) { + mos6522.setJoyStickPressed(MOS6522::Vic20JoyStickButton::Down, false); + } + if ( !(pik & MASK_JOY1_RIGHT) && (k & MASK_JOY1_RIGHT) ) { + mos6522.setJoyStickPressed(MOS6522::Vic20JoyStickButton::Right, true); + } + else if ( (pik & MASK_JOY1_RIGHT) && !(k & MASK_JOY1_RIGHT) ) { + mos6522.setJoyStickPressed(MOS6522::Vic20JoyStickButton::Right, false); + } + if ( !(pik & MASK_JOY1_LEFT) && (k & MASK_JOY1_LEFT) ) { + mos6522.setJoyStickPressed(MOS6522::Vic20JoyStickButton::Left, true); + } + else if ( (pik & MASK_JOY1_LEFT) && !(k & MASK_JOY1_LEFT) ) { + mos6522.setJoyStickPressed(MOS6522::Vic20JoyStickButton::Left, false); + } + } #ifndef TEECOMPUTER diff --git a/MCUME_teensy41/teensy20/v20.h b/MCUME_teensy41/teensy20/wrapemu.h similarity index 100% rename from MCUME_teensy41/teensy20/v20.h rename to MCUME_teensy41/teensy20/wrapemu.h diff --git a/MCUME_teensy41/teensy64/Teensy64.h b/MCUME_teensy41/teensy64/Teensy64.h index 3569c4a..6cf3527 100644 --- a/MCUME_teensy41/teensy64/Teensy64.h +++ b/MCUME_teensy41/teensy64/Teensy64.h @@ -53,14 +53,7 @@ extern "C" { #include "emuapi.h" } - -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#else -#include "tft_t_dma.h" -#endif -extern TFT_T_DMA tft; - +#include void initMachine(); void resetMachine() __attribute__ ((noreturn)); diff --git a/MCUME_teensy41/teensy64/cpu.h b/MCUME_teensy41/teensy64/cpu.h old mode 100755 new mode 100644 index 1c6c602..a641af6 --- a/MCUME_teensy41/teensy64/cpu.h +++ b/MCUME_teensy41/teensy64/cpu.h @@ -49,7 +49,7 @@ #include "Teensy64.h" #include "roms.h" #include "patches.h" -#include "util.h" +#include "timerutil.h" #include "pla.h" #include "vic.h" #include "keyboard.h" @@ -331,4 +331,4 @@ static inline uint8_t gpioRead(uint8_t pin) } -#endif \ No newline at end of file +#endif diff --git a/MCUME_teensy41/teensy64/emuapi.cpp b/MCUME_teensy41/teensy64/emuapi.cpp index a374cf7..e128cca 100644 --- a/MCUME_teensy41/teensy64/emuapi.cpp +++ b/MCUME_teensy41/teensy64/emuapi.cpp @@ -5,25 +5,31 @@ extern "C" { #include "iopins.h" } -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#else -#include "tft_t_dma.h" -#endif +#include -#ifdef HAS_USBKEY +#ifdef HAS_USB #include "USBHost_t36.h" // Read this header first for key info USBHost myusb; USBHub hub1(myusb); +#ifdef HAS_USBKEY KeyboardController keyboard1(myusb); USBHIDParser hid1(myusb); MouseController mouse1(myusb); +#endif +#ifdef HAS_USBMIDI MIDIDevice midi1(myusb); #endif +#ifdef HAS_USBJOY +#define COUNT_JOYSTICKS 4 +JoystickController joysticks[COUNT_JOYSTICKS](myusb); +#endif +#endif static bool emu_writeConfig(void); static bool emu_readConfig(void); static bool emu_eraseConfig(void); +static bool emu_writeGfxConfig(char * display_type); +static int emu_readGfxConfig(void); static bool mouseDetected = false; static bool keyboardDetected = false; @@ -34,12 +40,13 @@ static File file; #define MAX_FILES 64 #define AUTORUN_FILENAME "autorun.txt" +#define GFX_CFG_FILENAME "gfxmode.txt" -#define MAX_FILENAME_SIZE 24 +#define MAX_FILENAME_SIZE 34 #define MAX_MENULINES 9 #define TEXT_HEIGHT 16 #define TEXT_WIDTH 8 -#define MENU_FILE_XOFFSET (6*TEXT_WIDTH) +#define MENU_FILE_XOFFSET (2*TEXT_WIDTH) #define MENU_FILE_YOFFSET (2*TEXT_HEIGHT) #define MENU_FILE_W (MAX_FILENAME_SIZE*TEXT_WIDTH) #define MENU_FILE_H (MAX_MENULINES*TEXT_HEIGHT) @@ -53,7 +60,8 @@ static File file; #define MENU_VGA_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) #define MENU_VGA_YOFFSET (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37) -extern TFT_T_DMA tft; +#include "t4_dsp.h" +T4_DSP tft; static int nbFiles=0; static int curFile=0; @@ -65,6 +73,8 @@ static char selected_filename[MAX_FILENAME_SIZE]=""; static char second_selected_filename[MAX_FILENAME_SIZE]=""; static bool menuRedraw=true; static bool autorun=false; +static bool vgahires=false; + static const unsigned short * keys; #ifdef TEECOMPUTER @@ -158,6 +168,29 @@ void emu_Free(void * pt) free(pt); } +#define SMEMPOOL (0x800000) +EXTMEM static unsigned char slowmem[SMEMPOOL]; +static int slowmempt = 0; + +void * emu_SMalloc(unsigned int size) +{ + void * mem = (void*)&slowmem[slowmempt]; + slowmempt += size; + + if ( slowmempt > SMEMPOOL ) { + mem = NULL; + emu_printf("failure to allocate slow"); + } + else { + emu_printf("could allocate slow static "); + emu_printf(size); + } + return mem; +} + +void emu_SFree(void * pt) +{ +} /******************************** * Input and keyboard ********************************/ @@ -329,6 +362,12 @@ int emu_ReadKeys(void) #endif if ( row & 0x02 ) retval |= MASK_JOY2_BTN; + +#ifdef EXTPAD + if ( sh_pressed ) retval |= MASK_KEY_USER3; + if ( fn_pressed ) retval |= MASK_KEY_USER1; + digitalWrite(KLED, 0); +#else // Handle LED flash uint32_t time_ms=millis(); if ((time_ms-last_t_ms) > 100) { @@ -412,8 +451,9 @@ int emu_ReadKeys(void) if ( key_fn ) retval |= MASK_KEY_USER2; if ( ( key_fn ) && (keymatrix[4] == 0x10 )) retval |= MASK_KEY_USER1; +#endif - if ( (key_fn) && (key_sh) ) + if ( (fn_pressed) && (sh_pressed) ) #else if ( ((retval & (MASK_KEY_USER1+MASK_KEY_USER2)) == (MASK_KEY_USER1+MASK_KEY_USER2)) || (retval & MASK_KEY_USER4 ) ) @@ -453,8 +493,10 @@ int emu_ReadKeys(void) while (true) { ; } -#endif +#endif } + + emu_GetJoystick(); return (retval); } @@ -607,7 +649,7 @@ int emu_setKeymap(int index) { } int emu_GetMouse(int *x, int *y, int *buts) { -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBKEY) if (mouse1.available()) { *buts = mouse1.getButtons(); *x = mouse1.getMouseX(); @@ -620,7 +662,23 @@ int emu_GetMouse(int *x, int *y, int *buts) { return 0; } -#ifdef HAS_USBKEY +int emu_GetJoystick(void) { +#if defined(HAS_USB) && (HAS_USBJOY) + for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) { + if (joysticks[joystick_index].available()) { + uint64_t axis_mask = joysticks[joystick_index].axisMask(); + uint64_t axis_changed_mask = joysticks[joystick_index].axisChangedMask(); + uint32_t buttons = joysticks[joystick_index].getButtons(); + Serial.printf("Joystick(%d): buttons = %x", joystick_index, buttons); + Serial.println(); + } + } + return 1; +#endif + return 0; +} + +#if defined(HAS_USB) && (HAS_USBKEY) void OnPress(auto key) { keyboardDetected = true; @@ -764,7 +822,7 @@ int emu_KeyboardDetected(void) { return (keyboardDetected?1:0); } -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) static unsigned char midiBuffer[16]; static unsigned char midiLastCmd=0; static int midiDataCnt=0; @@ -772,8 +830,7 @@ static int midiCmdNbParam=0; #endif void emu_MidiOnDataReceived(unsigned char value) { - -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) //Serial.println(value, HEX); //10000000 = 128 = note off //10010000 = 144 = note on @@ -941,6 +998,7 @@ void emu_MidiOnDataReceived(unsigned char value) { /******************************** * Menu file loader UI ********************************/ +#ifdef FILEBROWSER static int readNbFiles(void) { int totalFiles = 0; @@ -970,8 +1028,6 @@ static int readNbFiles(void) { return totalFiles; } - - void backgroundMenu(void) { menuRedraw=true; tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00)); @@ -981,11 +1037,13 @@ void backgroundMenu(void) { int handleMenu(uint16_t bClick) { if (autorun) { + toggleMenu(false); + menuRedraw=false; return (ACTION_RUN1); } int action = ACTION_NONE; - if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) ) { + if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) || ( bClick & MASK_KEY_USER2 ) ) { char newpath[MAX_FILENAME_PATH]; strcpy(newpath, selection); strcat(newpath, "/"); @@ -996,17 +1054,31 @@ int handleMenu(uint16_t bClick) File file = SD.open(selection); if (file.isDirectory()) { curFile = 0; - nbFiles = readNbFiles(); + nbFiles = readNbFiles(); + menuRedraw=true; } - else { - action = ACTION_RUN1; + else + { #ifdef TEECOMPUTER - if (key_extmode) { + if ( (key_extmode) || ( key_sh) ) { emu_writeConfig(); } + if ( tft.getMode() < MODE_VGA_320x240) { + if ( bClick & MASK_KEY_USER2 ) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + } + //emu_SwapJoysticks(0); #endif + toggleMenu(false); + menuRedraw=false; + return (ACTION_RUN1); } - menuRedraw=true; } else if ( bClick & MASK_KEY_USER1 ) { menuRedraw=true; @@ -1015,19 +1087,14 @@ int handleMenu(uint16_t bClick) strcat(second_selection, "/"); strcat(second_selection, second_selected_filename); action = ACTION_RUN2; - } - else if ( bClick & MASK_KEY_USER2 ) { - menuRedraw=true; - //action = ACTION_RUN3; - emu_SwapJoysticks(0); - } + } else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) { if (curFile!=0) { menuRedraw=true; curFile--; } } - else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { + else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { if ((curFile-9)>=0) { menuRedraw=true; curFile -= 9; @@ -1042,7 +1109,7 @@ int handleMenu(uint16_t bClick) menuRedraw=true; } } - else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { + else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { if ((curFile<(nbFiles-9)) && (nbFiles)) { curFile += 9; menuRedraw=true; @@ -1099,12 +1166,12 @@ int handleMenu(uint16_t bClick) return (action); } -bool menuActive(void) +int menuActive(void) { - return (menuOn); + return (menuOn?1:0); } -void toggleMenu(bool on) { +void toggleMenu(int on) { if (on) { menuOn=true; backgroundMenu(); @@ -1122,7 +1189,7 @@ char * menuSecondSelection(void) { return (second_selection); } - +#endif /******************************** * OSKB handling @@ -1140,8 +1207,9 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) char c[4] = {' ',0,' ',0}; const char * cpt = str; int i=0; - int fb_width,fb_height,fb_stride; - tft.get_frame_buffer_size(&fb_width, &fb_height, &fb_stride); + int fb_width,fb_height,fbstride; + + fbstride = tft.get_frame_buffer_size(&fb_width, &fb_height); int ypos = (bottom?(fb_height-2*8):0); int line = row + (bottom?2:0); while ((c[1] = *cpt++)) @@ -1150,7 +1218,7 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0); else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff); if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff); - tft.drawTextNoDma(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); + tft.drawText(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); i++; } } @@ -1248,7 +1316,7 @@ int handleOSKB(void) { return retval; } -void toggleOSKB(bool forceon) { +void toggleOSKB(int forceon) { if (forceon) { oskbOn = true; drawOSKB(); @@ -1332,6 +1400,17 @@ int emu_FileRead(void * buf, int size, int handler) #endif } +int emu_FileWrite(void * buf, int size, int handler) +{ +// emu_printf("emu_FileWrite"); +// emu_printi(handler); +#ifdef HCFH + return (file.write(buf, size)); +#else + return (getFileHandler(handler).write(buf, size)); +#endif +} + int emu_FileGetc(int handler) { // emu_printf("FileGetc"); // emu_printi(handler); @@ -1404,6 +1483,9 @@ unsigned int emu_FileSize(const char * filepath) emu_printf(filesize); lofile.close(); } + else { + emu_printf("filesize failed"); + } return(filesize); } @@ -1489,6 +1571,48 @@ static bool emu_eraseConfig(void) SD.remove (ROMSDIR "/" AUTORUN_FILENAME); } +static bool emu_writeGfxConfig(char * display_type) +{ + bool retval = false; + SD.remove ("/" GFX_CFG_FILENAME); + if (strcmp(display_type, "VGA")) { + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(display_type, strlen(display_type)) != strlen(display_type)) { + emu_printf("GFX config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + } + return retval; +} + +#define CFG_VGA 0 +#define CFG_ILI 1 +#define CFG_ST 2 + +static int emu_readGfxConfig(void) +{ + int retval = CFG_VGA; // No file = VGA + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + if (filesize == 2) // "ST" + { + retval = CFG_ST; + } + else if (filesize == 3) // "ILI" + { + retval = CFG_ILI; + } + lofile.close(); + } + return retval; +} + /******************************** * File IO compatibility ********************************/ @@ -1670,62 +1794,249 @@ FRESULT f_mkdir (const char* path) /******************************** - * Initialization + * GFX wrapper ********************************/ -void emu_init(void) +static unsigned short palette16[PALETTE_SIZE]; +static IntervalTimer myTimer; +volatile boolean vbl=true; +volatile boolean vgatimervsync=false; +static void (*vblCallback)(void) = nullptr; +static int skip=0; + +static void vblCount() { + if (vbl) { + vbl = false; + } else { + vbl = true; + } +} + +void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) +{ + if (index= MODE_VGA_320x240 ) { + if (vgatimervsync) { + while (vbl==vb) {}; + } + else { + tft.waitSync(); + } + } + else { + while (vbl==vb) {}; + } + if (vblCallback != nullptr) { + vblCallback(); + } +} + +void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride) +{ + if (skip == 0) { + tft.writeScreenPal(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); + } +} +void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLinePal(width,height,line, VBuf, palette16); + } +} + +void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine(width,height,line, VBuf); + } +} + +void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine8(width,height,line, VBuf, palette16); + } +} + +int emu_IsVga(void) +{ + return (tft.getMode() >= MODE_VGA_320x240?1:0); +} + +int emu_IsVgaHires(void) +{ + return (tft.getMode() >= MODE_VGA_640x240?1:0); +} + +int emu_FrameSkip(void) +{ + return skip; +} + + +/******************************** + * AUDIO wrapper +********************************/ +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +AudioPlaySystem mymixer; + +void emu_sndInit() { + Serial.println("sound init"); + mymixer.begin_audio(256, mymixer.snd_Mixer); + mymixer.start(); +} + +void emu_sndPlaySound(int chan, int volume, int freq) +{ + if (chan < 6) { + mymixer.sound(chan, freq, volume); + } + /* + Serial.print(chan); + Serial.print(":" ); + Serial.print(volume); + Serial.print(":" ); + Serial.println(freq); + */ +} + +void emu_sndPlayBuzz(int size, int val) { + mymixer.buzz(size,val); + //Serial.print((val==1)?1:0); + //Serial.print(":"); + //Serial.println(size); +} +#endif + +/******************************** + * Initialization +********************************/ +void emu_init(int hires) { Serial.begin(115200); + vgahires = hires; -#ifdef HAS_USBKEY +#ifdef HAS_USB myusb.begin(); +#ifdef HAS_USBKEY keyboard1.attachPress(OnPress); keyboard1.attachRelease(OnRelease); #endif +#endif - while (!SD.begin(SD_CS)) +#ifdef FILEBROWSER + if (!SD.begin(SD_CS)) { - Serial.println("SD begin failed, retrying..."); - delay(1000); + Serial.println("No SD card detected"); } strcpy(selection,ROMSDIR); - FileHandlersInit(); - nbFiles = readNbFiles(); - - Serial.print("SD initialized, files found: "); Serial.println(nbFiles); +#endif emu_InitJoysticks(); #ifdef SWAP_JOYSTICK - joySwapped = true; + joySwapped = true; #else - joySwapped = false; + joySwapped = false; #endif -#ifdef TEECOMPUTER -#ifndef HAS_T4_VGA - tft.flipscreen(false); -#endif -#endif int keypressed = emu_ReadKeys(); +#ifdef HAS_T4_VGA + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } +#else + int gfx_mode = CFG_VGA; // default +#ifdef FILEBROWSER + gfx_mode = emu_readGfxConfig(); +#endif + // Force VGA if UP pressed + if (keypressed & MASK_JOY2_UP) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("VGA"); +#endif + gfx_mode = CFG_VGA; + } + else { + if (keypressed & MASK_JOY2_LEFT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ST"); +#endif + gfx_mode = CFG_ST; + } + else if (keypressed & MASK_JOY2_RIGHT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ILI"); +#endif + gfx_mode = CFG_ILI; + } + } + if (gfx_mode == CFG_VGA) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + else + { + tft.begin(gfx_mode == CFG_ILI?MODE_TFTILI_320x240:MODE_TFTST_320x240); + } +#endif + if (keypressed & MASK_JOY2_DOWN) { tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) ); tft.drawTextNoDma(64,48, (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); +#ifdef FILEBROWSER emu_eraseConfig(); delay(1000); +#endif } else { +#ifdef FILEBROWSER if (emu_readConfig()) { autorun = true; } +#endif } +#ifdef FILEBROWSER toggleMenu(true); +#endif } -void emu_start(void) +void emu_start(int vblms, void * callback, int forcetimervsync) { + vgatimervsync = forcetimervsync?true:false; + tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); + tft.startRefresh(); + if (callback != nullptr) { + vblCallback = callback; + } + + myTimer.begin(vblCount, vblms); +#ifdef HAS_SND + emu_sndInit(); +#endif usbnavpad = 0; } diff --git a/MCUME_teensy41/teensy64/emuapi.h b/MCUME_teensy41/teensy64/emuapi.h index 4122ef6..5dd6130 100644 --- a/MCUME_teensy41/teensy64/emuapi.h +++ b/MCUME_teensy41/teensy64/emuapi.h @@ -2,126 +2,14 @@ #define EMUAPI_H #include "platform_config.h" - -#define CUSTOM_SND 1 -//#define TIMER_REND 1 - -#define EXTRA_HEAP 0x10 - -// Title: < > -#define TITLE " C64 Emulator " -#define ROMSDIR "c64" - -#define emu_Init(ROM) {c64_Start(ROM); c64_Init(); } -#define emu_Step(x) { c64_Step(); } -#define emu_Input(x) { c64_Input(x); } - -#define MAX_FILENAME_PATH 64 -#define NB_FILE_HANDLER 4 -#define PALETTE_SIZE 256 -#define VID_FRAME_SKIP 0x0 -#define TFT_VBUFFER_YCROP 0 -#define SINGLELINE_RENDERING 1 - -#define R32(rgb) ((rgb>>16)&0xff) -#define G32(rgb) ((rgb>>8)&0xff) -#define B32(rgb) (rgb & 0xff) +#include "emucfg.h" #define ACTION_NONE 0 -#define ACTION_MAXKBDVAL 16 -#define ACTION_EXITKBD 128 -#define ACTION_RUN1 129 -#define ACTION_RUN2 130 -#define ACTION_RUN3 131 - - -#ifdef KEYMAP_PRESENT - -#define keylables_map0_0 (char *)"QWERTYUIOP\x1a" -#define keylables_map0_1 (char *)" ASDFGHJKL\x19" -#define keylables_map0_2 (char *)" ZXCVBNM,.;/" -#define keylables_map0_3 (char *)" +\x10-" -const unsigned short key_map0[] = { - 'Q','W','E','R','T','Y','U','I','O','P',127, //default C64 uppercase always - 0,'A','S','D','F','G','H','J','K','L',10, - 0,'Z','X','C','V','B','N','M',',','.',';','/', - 0,0,0,0, - 0,'+',' ','-' - }; - -#define keylables_map1_0 (char *)"1234567890 " -#define keylables_map1_1 (char *)" " -#define keylables_map1_2 (char *)" " -#define keylables_map1_3 (char *)" " - -const unsigned short key_map1[] = { - '1','2','3','4','5','6','7','8','9','0',0, // digit keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map2_0 (char *)"!\"#$%^&*()@" -#define keylables_map2_1 (char *)" " -#define keylables_map2_2 (char *)" <>:?" -#define keylables_map2_3 (char *)" =\x10_" -const unsigned short key_map2[] = { - '!','"','#','$','%','^','&','*','(',')','@', // shiftothers - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,'<','>',':','?', - 153,151,150,152, //U L R D - 0,'=',' ','_' - }; - -#define keylables_map3_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " -#define keylables_map3_1 (char *)" " -#define keylables_map3_2 (char *)" " -#define keylables_map3_3 (char *)" " - -const unsigned short key_map3[] = { - 129,130,131,132,133,134,135,136,0,0,0, // function keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map4_0 (char *)"QWERTYUIOP@" -#define keylables_map4_1 (char *)" ASDFGHJKL\x19" -#define keylables_map4_2 (char *)" ZXCVBNM<>:?" -#define keylables_map4_3 (char *)" =\x10_" -const unsigned short key_map4[] = { - 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase - 0,'A','S','D','F','G','H','J','K','L',10, - 0,'Z','X','C','V','B','N','M','<','>',':','?', - 0,0,0,0, - 0,'=',' ','_' - }; - -#define keylables_map5_0 (char *)" " -#define keylables_map5_1 (char *)" " -#define keylables_map5_2 (char *)" " -#define keylables_map5_3 (char *)" " - -const unsigned short key_map5[] = { - 0,0,0,0,0,0,0,0,0,0,0, // extra keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 153,151,150,152, //U L R D - 0,0,' ',0 - }; - -const unsigned short matkeys[] = { - 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 - 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 - 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 - 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN - 0x510,0x010,0x110,0x310, // row 4 - }; - -#endif +#define ACTION_RUN1 1 +#define ACTION_RUN2 2 +#define FORCE_VGATIMERVSYNC 1 +#define SUPPORT_HIRES 1 #define MASK_JOY2_RIGHT 0x0001 #define MASK_JOY2_LEFT 0x0002 @@ -138,22 +26,25 @@ const unsigned short matkeys[] = { #define MASK_JOY1_BTN 0x1000 #define MASK_KEY_USER4 0x2000 +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) #ifdef __cplusplus extern "C" { +extern void emu_init(int hires=0); +extern void emu_start(int vblms, void * callback, int forcetimervsync=0); #endif - -extern void emu_init(void); -extern void emu_start(void); extern void emu_printf(const char * text); extern void emu_printi(int val); extern void emu_printh(int val); extern void * emu_Malloc(unsigned int size); extern void * emu_MallocI(unsigned int size); extern void emu_Free(void * pt); +extern void * emu_SMalloc(unsigned int size); +extern void emu_SFree(void * pt); extern int emu_FileOpen(const char * filepath, const char * mode); extern int emu_FileRead(void * buf, int size, int handler); +extern int emu_FileWrite(void * buf, int size, int handler); extern int emu_FileGetc(int handler); extern int emu_FileSeek(int handler, int seek, int origin); extern int emu_FileTell(int handler); @@ -164,24 +55,23 @@ extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size); extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek); extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index); -extern void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride); -extern void emu_DrawLine(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line); extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line); +extern void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride); extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line); -extern void emu_CopyLine(int width, int height, int ysrc, int ydst); extern void emu_DrawVsync(void); extern int emu_FrameSkip(void); -extern void * emu_LineBuffer(int line); -extern void emu_tweakVideo(int shiftdelta, int numdelta, int denomdelta); +extern int emu_IsVga(void); +extern int emu_IsVgaHires(void); -extern bool menuActive(void); +extern int menuActive(void); extern char * menuSelection(void); extern char * menuSecondSelection(void); -extern void toggleMenu(bool on); +extern void toggleMenu(int on); extern int handleMenu(unsigned short bClick); extern int handleOSKB(void); -extern void toggleOSKB(bool forceon); +extern void toggleOSKB(int forceon); extern void emu_InitJoysticks(void); extern int emu_SwapJoysticks(int statusOnly); @@ -190,6 +80,7 @@ extern int emu_ReadKeys(void); extern int emu_GetPad(void); extern int emu_GetMouse(int *x, int *y, int *buts); extern int emu_MouseDetected(void); +extern int emu_GetJoystick(void); extern int emu_KeyboardDetected(void); extern int emu_ReadAnalogJoyX(int min, int max); extern int emu_ReadAnalogJoyY(int min, int max); diff --git a/MCUME_teensy41/teensy64/emucfg.h b/MCUME_teensy41/teensy64/emucfg.h new file mode 100644 index 0000000..d2d7b6f --- /dev/null +++ b/MCUME_teensy41/teensy64/emucfg.h @@ -0,0 +1,115 @@ +#ifndef EMUCFG_H +#define EMUCFG_H + +#include "wrapemu.h" + +// Title: < > +#define TITLE " C64 Emulator " +#define ROMSDIR "c64" + +#define emu_Init(ROM) {c64_Start(ROM); c64_Init(); } +#define emu_Step(x) { c64_Step(); } +#define emu_Input(x) { c64_Input(x); } + +#define MAX_FILENAME_PATH 64 +#define NB_FILE_HANDLER 4 + +#define PALETTE_SIZE 16 +#define VID_FRAME_SKIP 0x0 +#define TFT_VBUFFER_YCROP 0 +#define SINGLELINE_RENDERING 1 +#define CUSTOM_SND 1 +//#define TIMER_REND 1 +//#define EXTPAD 1 +#define EXTRA_HEAP 0x10 +#define FILEBROWSER 1 + + +#ifdef KEYMAP_PRESENT + +#define keylables_map0_0 (char *)"QWERTYUIOP\x1a" +#define keylables_map0_1 (char *)" ASDFGHJKL\x19" +#define keylables_map0_2 (char *)" ZXCVBNM,.;/" +#define keylables_map0_3 (char *)" +\x10-" +const unsigned short key_map0[] = { + 'Q','W','E','R','T','Y','U','I','O','P',127, //default C64 uppercase always + 0,'A','S','D','F','G','H','J','K','L',10, + 0,'Z','X','C','V','B','N','M',',','.',';','/', + 0,0,0,0, + 0,'+',' ','-' + }; + +#define keylables_map1_0 (char *)"1234567890 " +#define keylables_map1_1 (char *)" " +#define keylables_map1_2 (char *)" " +#define keylables_map1_3 (char *)" " + +const unsigned short key_map1[] = { + '1','2','3','4','5','6','7','8','9','0',0, // digit keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 153,151,150,152, //U L R D + 0,0,' ',0 + }; + +#define keylables_map2_0 (char *)"!\"#$%^&*()@" +#define keylables_map2_1 (char *)" " +#define keylables_map2_2 (char *)" <>:?" +#define keylables_map2_3 (char *)" =\x10_" +const unsigned short key_map2[] = { + '!','"','#','$','%','^','&','*','(',')','@', // shiftothers + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 153,151,150,152, //U L R D + 0,'=',' ','_' + }; + +#define keylables_map3_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " +#define keylables_map3_1 (char *)" " +#define keylables_map3_2 (char *)" " +#define keylables_map3_3 (char *)" " + +const unsigned short key_map3[] = { + 129,130,131,132,133,134,135,136,0,0,0, // function keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map4_0 (char *)"QWERTYUIOP@" +#define keylables_map4_1 (char *)" ASDFGHJKL\x19" +#define keylables_map4_2 (char *)" ZXCVBNM<>:?" +#define keylables_map4_3 (char *)" =\x10_" +const unsigned short key_map4[] = { + 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase + 0,'A','S','D','F','G','H','J','K','L',10, + 0,'Z','X','C','V','B','N','M','<','>',':','?', + 0,0,0,0, + 0,'=',' ','_' + }; + +#define keylables_map5_0 (char *)" " +#define keylables_map5_1 (char *)" " +#define keylables_map5_2 (char *)" " +#define keylables_map5_3 (char *)" " + +const unsigned short key_map5[] = { + 0,0,0,0,0,0,0,0,0,0,0, // extra keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 153,151,150,152, //U L R D + 0,0,' ',0 + }; + +const unsigned short matkeys[] = { + 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 + 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 + 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 + 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN + 0x510,0x010,0x110,0x310, // row 4 + }; + +#endif + +#endif diff --git a/MCUME_teensy41/teensy64/platform_config.h b/MCUME_teensy41/teensy64/platform_config.h index 8d006be..914d152 100644 --- a/MCUME_teensy41/teensy64/platform_config.h +++ b/MCUME_teensy41/teensy64/platform_config.h @@ -4,23 +4,26 @@ #define TEECOMPUTER 1 #ifdef TEECOMPUTER -//#define ILI9341 1 -//#define ST7789 1 -//#define TFTSPI1 1 -#define HAS_T4_VGA 1 +#define TFTSPI1 1 +//#define HAS_T4_VGA 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 -#define INVX 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 #define PT8211 1 #else #define HAS_T4_VGA 1 -#define HIRES 1 //#define INVX 1 #define INVY 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 +#define PT8211 1 #endif diff --git a/MCUME_teensy41/teensy64/t4_dsp.cpp b/MCUME_teensy41/teensy64/t4_dsp.cpp new file mode 100644 index 0000000..43301fa --- /dev/null +++ b/MCUME_teensy41/teensy64/t4_dsp.cpp @@ -0,0 +1,1774 @@ +/* + TFT/VGA driver + DMA TFT driver based on C64 ILI9341 dma driver from Frank Bösing, 2017 +*/ + +#include "T4_DSP.h" + +#include +#include + +#include "font8x8.h" + +// TFT constants and variables +#define TFT_LINEARINT 1 +#define LINEARINT_HACK 1 +#define DMA_LINES_PER_BLOCK 64 +#define DMA_NUM_SETTINGS 4 + +#define TFT_SWRESET 0x01 +#define TFT_SLPOUT 0x11 +#define TFT_INVON 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_MADCTL 0x36 +#define TFT_PIXFMT 0x3A +#define TFT_MADCTL_MY 0x80 +#define TFT_MADCTL_MX 0x40 +#define TFT_MADCTL_MV 0x20 +#define TFT_MADCTL_ML 0x10 +#define TFT_MADCTL_RGB 0x00 +#define TFT_MADCTL_BGR 0x08 +#define TFT_MADCTL_MH 0x04 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) +//#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) +//#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) +//#define R16(rgb) ((rgb>>8)&0xf8) +//#define G16(rgb) ((rgb>>3)&0xfc) +//#define B16(rgb) ((rgb<<3)&0xf8) + +// LPSPI4 = SPI0 in Teensy 4.0 +// LPSPI3 = SPI1 in Teensy 4.0 +// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) + +#ifdef TFTSPI1 +#define SPI SPI1 +#define LPSPIP_TDR LPSPI3_TDR +#define LPSPIP_CR LPSPI3_CR +#define LPSPIP_CFGR1 LPSPI3_CFGR1 +#define LPSPIP_TCR LPSPI3_TCR +#define LPSPIP_DER LPSPI3_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX +#else +#define LPSPIP_TDR LPSPI4_TDR +#define LPSPIP_CR LPSPI4_CR +#define LPSPIP_CFGR1 LPSPI4_CFGR1 +#define LPSPIP_TCR LPSPI4_TCR +#define LPSPIP_DER LPSPI4_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX +#endif + +#define SPICLOCK 60000000 +#define SPI_MODE SPI_MODE0 + +// VGA constants and macros +typedef uint8_t vga_pixel; +#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) + +static DMASetting dmasettings[DMA_NUM_SETTINGS]; +static DMAChannel dmatx; +static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K +static volatile uint8_t rstop = 0; +static volatile bool cancelled = false; +static volatile uint8_t curTransfer = 0; +static uint8_t nbTransfer = 0; +static uint16_t * tft_buffer; +static int tft_width; +static int tft_height; +static int tft_stride; + +#define DELAY_MASK 0x80 +PROGMEM static const uint8_t init_commands[] = { + 1+DELAY_MASK, TFT_SWRESET, 150, + 1+DELAY_MASK, TFT_SLPOUT, 255, + 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, + 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, + 1, TFT_INVON, + 1, TFT_DISPON, + 0 +}; + +// VGA constants and variables +// Objective: +// generates VGA signal fully in hardware with as little as possible CPU help + +// Principle: +// QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) +// 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate +// RGB out, combined to create 8bits(/12bits) output. + +// Note: +// - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels +// - experimental resolution: 352x240,352x480 +// - experimental resolution: 512x240,512x480 (not stable) +// - video memory is allocated using malloc in T4 heap +// - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing +// but tried to be compensated by pixel shifting +// - Default is 8bits RRRGGGBB (332) +// But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! +// - Only ok at 600MHz else some disturbances visible + + + +#define TOP_BORDER 40 +#define PIN_HBLANK 15 + +#define PIN_R_B2 33 +#define PIN_R_B1 4 +#define PIN_R_B0 3 +#define PIN_G_B2 2 +#define PIN_G_B1 13 +#define PIN_G_B0 11 +#define PIN_B_B1 12 +#define PIN_B_B0 10 + + +#define DMA_HACK 0x80 + +#define R16(rgb) ((rgb>>8)&0xf8) +#define G16(rgb) ((rgb>>3)&0xfc) +#define B16(rgb) ((rgb<<3)&0xf8) + +// VGA 640x480@60Hz +// Screen refresh rate 60 Hz +// Vertical refresh 31.46875 kHz +// Pixel freq. 25.175 MHz +// +// Visible area 640 25.422045680238 us +// Front porch 16 0.63555114200596 us +// Sync pulse 96 3.8133068520357 us +// Back porch 48 1.9066534260179 us +// Whole line 800 31.777557100298 us + +#define frame_freq 60.0 // Hz +#define line_freq 31.46875 // KHz +#define pix_freq (line_freq*800) // KHz (25.175 MHz) + +// pix_period = 39.7ns +// H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) +#define frontporch_pix 20 //16 +#define backporch_pix 44 //48 + +// Flexio Clock +// PLL3 SW CLOCK (3) => 480 MHz +// PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) +#define FLEXIO_CLK_SEL_PLL3 3 +#define FLEXIO_CLK_SEL_PLL5 2 + +/* Set video PLL */ +// There are /1, /2, /4, /8, /16 post dividers for the Video PLL. +// The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, +// and CCM_ANALOG_MISC2 register sets according to the following equation. +// PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + +// nfact: +// This field controls the PLL loop divider. +// Valid range for DIV_SELECT divider value: 27~54. + +#define POST_DIV_SELECT 2 + +// Full buffer including back/front porch +static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; +static uint32_t dstbuffer __attribute__((aligned(32))); + +// Visible vuffer +static vga_pixel * vga_buffer; +static int vga_width; +static int vga_height; +static int vga_stride; + +static int maxpixperline; +static int left_border; +static int right_border; +static int line_double; +static int pix_shift; +static int ref_div_select; +static int ref_freq_num; +static int ref_freq_denom; +static int ref_pix_shift; +static int combine_shiftreg; + +#ifdef DEBUG +static uint32_t ISRTicks_prev = 0; +volatile uint32_t ISRTicks = 0; +#endif + +uint8_t T4_DSP::_rst; +uint8_t T4_DSP::_cs; +uint8_t T4_DSP::_dc; +uint8_t T4_DSP::_mosi; +uint8_t T4_DSP::_sclk; +uint8_t T4_DSP::_vsync_pin = -1; +DMAChannel T4_DSP::flexio1DMA; +DMAChannel T4_DSP::flexio2DMA; + +static volatile uint32_t VSYNC = 0; +static volatile uint32_t currentLine=0; +#define NOP asm volatile("nop\n\t"); +static gfx_mode_t gfxmode = MODE_UNDEFINED; + + +FASTRUN void T4_DSP::TFT_isr(void) { + dmatx.clearInterrupt(); + curTransfer++; + if (curTransfer >= nbTransfer) { + curTransfer = 0; + if (cancelled) { + dmatx.disable(); + rstop = 1; + } + } + arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); +} + +FASTRUN void T4_DSP::QT3_isr(void) { + TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); + TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); + + cli(); + + // V-PULSE + if (currentLine > 0) { + digitalWrite(_vsync_pin, 1); + VSYNC = 0; + } else { + digitalWrite(_vsync_pin, 0); + VSYNC = 1; + } + + currentLine++; + currentLine = currentLine % 525; + + + uint32_t y = (currentLine - TOP_BORDER) >> line_double; + // Visible area + + if (y >= 0 && y < vga_height) { + // Disable DMAs + //DMA_CERQ = flexio2DMA.channel; + //DMA_CERQ = flexio1DMA.channel; + + // Setup source adress + // Aligned 32 bits copy + unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; + flexio2DMA.TCD->SADDR = p; + if (pix_shift & DMA_HACK) + { + // Unaligned copy + uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; + flexio1DMA.TCD->SADDR = p2; + } + else { + p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 + flexio1DMA.TCD->SADDR = p; + } + + // Enable DMAs + //flexio2DMA.enable(); + //flexio1DMA.enable(); + DMA_SERQ = flexio2DMA.channel; + DMA_SERQ = flexio1DMA.channel; + arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); + } + sei(); + +#ifdef DEBUG + ISRTicks++; +#endif + asm volatile("dsb"); +} + +static void setDmaStruct() { + uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; + uint16_t * fb = (uint16_t*)malloc(remaining); + tft_buffer = fb; + tft_width = TFT_WIDTH; + tft_height = TFT_HEIGHT; + tft_stride = TFT_WIDTH; + uint16_t col=RGBVAL16(0x00,0x00,0x00); + int i=0; + while (remaining > 0) { + int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); + blocks[i] = fb; + for (int j=0;jATTR_DST = 1; + dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); + dmasettings[i].interruptAtCompletion(); + fb += len/2; + remaining -= len; + i++; + } + dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); + nbTransfer = i; +} + +static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 +{ +//if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; + CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE + | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 + | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); + CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; + CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock + const int div_post_pll = 1; // other values: 2,4 + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass +} + +T4_DSP::T4_DSP() +{ + _cs = TFT_CS; + _dc = TFT_DC; + _rst = TFT_RST; + _mosi = TFT_MOSI; + _sclk = TFT_SCLK; + pinMode(_dc, OUTPUT); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, 1); + digitalWrite(_dc, 1); + _vsync_pin = 8; +} + + +void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { + int dx=0; + int dy=0; + digitalWrite(_dc, 0); + SPI.transfer(TFT_CASET); + digitalWrite(_dc, 1); + SPI.transfer16(x1+dx); + digitalWrite(_dc, 1); + SPI.transfer16(x2+dx); + digitalWrite(_dc, 0); + SPI.transfer(TFT_PASET); + digitalWrite(_dc, 1); + SPI.transfer16(y1+dy); + digitalWrite(_dc, 1); + SPI.transfer16(y2+dy); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + return; +} + +void T4_DSP::tft_setup(bool isST) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + // RESET if reset pin defined + if (_rst != 0xff) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + const uint8_t *addr = init_commands; + uint8_t count; + digitalWrite(_cs, 0); + while (count = *addr++) { + uint8_t command = *addr++; + if ( (command == TFT_INVON) && (!isST) ) { + // Skip TFT_INVON for ILI + } + else { + digitalWrite(_dc, 0); // command + SPI.transfer(command); + uint16_t ms = count & DELAY_MASK; + count &= ~DELAY_MASK; + while (--count > 0) { // data + uint8_t data = *addr++; + if ( (command == TFT_MADCTL) && (isST) ) { + data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; + } + digitalWrite(_dc, 1); + SPI.transfer(data); + } + if (ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + digitalWrite(_cs, 1); + SPI.endTransaction(); + delay(2); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + } + } + } + digitalWrite(_cs, 1); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + SPI.endTransaction(); + /* + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_dc, 0); + digitalWrite(_cs, 0); + SPI.transfer(TFT_MADCTL); + digitalWrite(_dc, 1); + SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); + // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); + digitalWrite(_cs, 1); + SPI.endTransaction(); + */ + cancelled = false; +} + +// display VGA image +gfx_error_t T4_DSP::begin(gfx_mode_t mode) +{ + uint32_t flexio_clock_div; + combine_shiftreg = 0; +// int div_select = 49; +// int num = 135; +// int denom = 100; + int div_select = 20; + int num = 9800; + int denom = 10000; + int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; + int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; + set_videoClock(div_select,num,denom,true); + +#ifdef DEBUG + Serial.println(mode); + Serial.println("mode"); +#endif + + switch(mode) + { + case MODE_TFTILI_320x240: +#ifdef DEBUG + Serial.println("TFTILI_320x240"); +#endif + tft_setup(false); + gfxmode = mode; + break; + case MODE_TFTST_320x240: +#ifdef DEBUG + Serial.println("TFTST_320x240"); +#endif + tft_setup(true); + gfxmode = mode; + break; + + case MODE_VGA_320x240: +#ifdef DEBUG + Serial.println("VGA_320x240"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_320x480: +#ifdef DEBUG + Serial.println("VGA_320x480"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_640x240: +#ifdef DEBUG + Serial.println("VGA_640x240"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/pix_freq; + line_double = 1; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_640x480: +#ifdef DEBUG + Serial.println("VGA_640x480"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = (flexio_freq/pix_freq); + line_double = 0; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_512x240: +#ifdef DEBUG + Serial.println("VGA_512x240"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 1; + pix_shift = 0; + break; + + case MODE_VGA_512x480: +#ifdef DEBUG + Serial.println("VGA_512x480"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 0; + pix_shift = 0; + break; + + case MODE_VGA_352x240: +#ifdef DEBUG + Serial.println("VGA_352x240"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_352x480: +#ifdef DEBUG + Serial.println("VGA_352x480"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + } + + if (mode >= MODE_VGA_320x240) + { + if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { + fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); + digitalWrite(_cs, 0); + digitalWrite(_dc, 0); + SPI.transfer(TFT_DISPOFF); + digitalWrite(_cs, 1); + delay(20); + digitalWrite(_cs, 0); + digitalWrite(_cs, 1); + } + gfxmode = mode; + + maxpixperline = vga_stride; + // Save param for tweek adjustment + ref_div_select = div_select; + ref_freq_num = num; + ref_freq_denom = denom; + ref_pix_shift = pix_shift; + +#ifdef DEBUG + Serial.println("frequency"); + Serial.println(flexio_freq); + Serial.println("div"); + Serial.println(flexio_freq/pix_freq); +#endif + + pinMode(_vsync_pin, OUTPUT); + pinMode(PIN_HBLANK, OUTPUT); + + /* Basic pin setup FlexIO1 */ + pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 + pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 + pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 + pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 + /* Basic pin setup FlexIO2 */ + pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 + pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 + pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 + pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 + + /* High speed and drive strength configuration */ + *(portControlRegister(PIN_G_B2)) = 0xFF; + *(portControlRegister(PIN_R_B0)) = 0xFF; + *(portControlRegister(PIN_R_B1)) = 0xFF; + *(portControlRegister(PIN_R_B2)) = 0xFF; + *(portControlRegister(PIN_B_B0)) = 0xFF; + *(portControlRegister(PIN_B_B1)) = 0xFF; + *(portControlRegister(PIN_G_B0)) = 0xFF; + *(portControlRegister(PIN_G_B1)) = 0xFF; + + /* Set clock for FlexIO1 and FlexIO2 */ + CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) + | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); + CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) + | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); + + + /* Set up pin mux FlexIO1 */ + *(portConfigRegister(PIN_G_B2)) = 0x14; + *(portConfigRegister(PIN_R_B0)) = 0x14; + *(portConfigRegister(PIN_R_B1)) = 0x14; + *(portConfigRegister(PIN_R_B2)) = 0x14; + /* Set up pin mux FlexIO2 */ + *(portConfigRegister(PIN_B_B0)) = 0x14; + *(portConfigRegister(PIN_B_B1)) = 0x14; + *(portConfigRegister(PIN_G_B0)) = 0x14; + *(portConfigRegister(PIN_G_B1)) = 0x14; + + /* Enable the clock */ + CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + /* Enable the FlexIO with fast access */ + FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + + uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; + uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; + + /* Shifter 0 registers for FlexIO2 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 + inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter + stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled + startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable + timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 + timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock + pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output + pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity + shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode + /* Shifter 0 registers for FlexIO1 */ + FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + /* Shifter 0 registers for FlexIO1 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 + FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + if (combine_shiftreg) { + pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled + FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + } + /* Timer 0 registers for FlexIO2 */ + timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset + timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output + timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset + timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare + timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert + stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled + startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled + if (combine_shiftreg) { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag + } + else { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag + } + triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low + triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected + pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled + //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 + //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high + timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode + // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) + + int shifts_per_transfer; + if (combine_shiftreg) { + shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 + } + else { + shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 + } + FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); + /* Timer 0 registers for FlexIO1 */ + FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); +#ifdef DEBUG + Serial.println("FlexIO setup complete"); +#endif + + /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ + if (combine_shiftreg) { + FLEXIO2_SHIFTSDEN |= (1<<1); + FLEXIO1_SHIFTSDEN |= (1<<1); + } + else { + FLEXIO2_SHIFTSDEN |= (1<<0); + FLEXIO1_SHIFTSDEN |= (1<<0); + } + /* Disable DMA channel so it doesn't start transferring yet */ + flexio1DMA.disable(); + flexio2DMA.disable(); + /* Set up DMA channel to use Shifter 0 trigger */ + flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); + flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); + + + if (combine_shiftreg) { + flexio2DMA.TCD->NBYTES = 8; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 8; + flexio2DMA.TCD->CITER = maxpixperline / 8; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + flexio1DMA.TCD->NBYTES = 8; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 8; + flexio1DMA.TCD->CITER = maxpixperline / 8; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Setup DMA2 Flexio2 copy + flexio2DMA.TCD->NBYTES = 4; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 4; + flexio2DMA.TCD->CITER = maxpixperline / 4; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + // Setup DMA1 Flexio1 copy + // Use pixel shift to avoid color smearing? + if (pix_shift & DMA_HACK) + { + if (pix_shift & 0x3 == 0) { + // Aligned 32 bits copy (32bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Unaligned (source) 32 bits copy (8bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 1; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion + } + } + else + { + // Aligned 32 bits copy + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + } + +#ifdef DEBUG + Serial.println("DMA setup complete"); +#endif + + // enable clocks for QTIMER3: generates the 15KHz for hsync + // Pulse: + // low : 3.8133 us => 569x6.7ns + // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) + // (OLD TEST) + // (4us low, 28us high => 32us) + // (597x6.7ns for 4us) + // (4179x6.7ns for 28us) + CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 + //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 + + #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz + #define MARGIN_D 1000 + + TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer + // Invert output pin as we want the interupt on rising edge + TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) + TMR3_CNTR3 = 0; + TMR3_LOAD3 = 0; + + /* Inverted timings */ + unsigned long long cpu_freq = F_CPU; + unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; + int rate2 = rate; + + int substract = 1; + if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { + substract=5; + rate2=1652; + } + + #ifdef DEBUG + Serial.print("MARGIN_N is: "); + Serial.println(rate2, DEC); + Serial.print("SUBSTRACT is: "); + Serial.println(substract, DEC); +#endif + TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; + TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; + /* + TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; + */ + TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on + TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), + // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) + //configure Teensy pin Compare output + IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 + attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function + NVIC_ENABLE_IRQ(IRQ_QTIMER3); +#ifdef DEBUG + Serial.println("QTIMER3 setup complete"); + Serial.print("V-PIN is "); + Serial.println(_vsync_pin); +#endif + + /* initialize gfx buffer */ + if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift + if (gfxbuffer == NULL) return(GFX_ERROR); +#ifdef DEBUG + Serial.println("Memory allocated"); +#endif + + memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); + vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; +#ifdef DEBUG + Serial.println(vga_stride); + Serial.println(vga_height); + Serial.println("Screen cleared"); +#endif + } + + return(GFX_OK); +} + +gfx_mode_t T4_DSP::getMode(void) +{ + return gfxmode; +} + +void T4_DSP::startRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + curTransfer = 0; + rstop = 0; + //dmatx.begin(true); + dmatx.attachInterrupt(TFT_isr); + setDmaStruct(); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + + digitalWrite(_cs, HIGH); + SPI.begin(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + + LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: + LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX + LPSPIP_TCR = 15; // Framesize 16 Bits + //LPSPIP_FCR = 0; // Fifo Watermark + LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable + LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: + dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); + + dmatx = dmasettings[0]; + digitalWrite(_cs, 0); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + dmatx.enable(); + } +} + + +void T4_DSP::stopRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + rstop = 1; + unsigned long m = millis(); + cancelled = true; + while (!rstop) { + if ((millis() - m) > 100) break; + delay(10); + asm volatile("wfi"); + }; + rstop = 0; + delay(50); + cancelled = false; + dmatx.detachInterrupt(); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + SPI.end(); +#ifdef ST7789 +// begin(gfxmode); +#endif + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + } +} + +int T4_DSP::get_frame_buffer_size(int *width, int *height) { + if (gfxmode < MODE_VGA_320x240) { + if (width != nullptr) *width = tft_width; + if (height != nullptr) *height = tft_height; + return tft_stride; + } + else { + if (width != nullptr) *width = vga_width; + if (height != nullptr) *height = vga_height; + return vga_stride; + } +} + +void T4_DSP::waitSync() +{ + if (gfxmode >= MODE_VGA_320x240) { + while (VSYNC == 0) {}; + } +} + +void T4_DSP::waitLine(int line) +{ + if (gfxmode >= MODE_VGA_320x240) { + while (currentLine != line) {}; + } +} + +/*********************************************************************************************** + No DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreenNoDma(uint16_t color) { + if (gfxmode < MODE_VGA_320x240) { + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + int i,j; + for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(arx, ary, arx+arw-1, ary+arh-1); + bitmap = bitmap + bmp_offy*w + bmp_offx; + for (int row=0;row> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + bits = *charpt++; + //digitalWrite(_dc, 1); + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + x +=8; + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + else { + drawText(x, y, text, fgcolor, bgcolor, doublesize); + } +} + + +/*********************************************************************************************** + DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreen(uint16_t color) { + int i,j; + if (gfxmode < MODE_VGA_320x240) { + for (j=0; j> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + dst=&tft_buffer[l*tft_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + x +=8; + } + } + else { + vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); + vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); + vga_pixel * dst; + while ((c = *text++)) { + const unsigned char * charpt=&font8x8[c][0]; + int l=y; + for (int i=0;i<8;i++) + { + unsigned char bits; + if (doublesize) { + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + x +=8; + } + } +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { + drawSprite(x,y,bitmap, 0,0,0,0); +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) +{ + int bmp_offx = 0; + int bmp_offy = 0; + uint16_t *bmp_ptr; + int w =*bitmap++; + int h = *bitmap++; + if ( (arw == 0) || (arh == 0) ) { + // no crop window + arx = x; + ary = y; + arw = w; + arh = h; + } + else { + if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + int l=ary; + bitmap = bitmap + bmp_offy*w + bmp_offx; + + if (gfxmode < MODE_VGA_320x240) { + for (int row=0;row tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]; + pos +=step; + } + #endif + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i 2) ) y += (tft_height-height)/2; + uint16_t * dst=&tft_buffer[y*tft_stride]; + if (width > tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]]; + pos +=step; + } +#endif + } + else if ((width*2) == tft_width) { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]]; + *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i tft_width) { + int step = ((width << 8)/tft_width); + int pos = 0; + for (int i=0; i> 8]]; + pos +=step; + } + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = pix; + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i +#include +#endif + +#include "platform_config.h" +#include "iopins.h" + + + +#ifndef TFT_WIDTH +#define TFT_WIDTH 320 +#endif +#define TFT_REALWIDTH 320 + +#ifndef TFT_HEIGHT +#define TFT_HEIGHT 240 +#endif +#define TFT_REALHEIGHT 240 + + +typedef enum gfx_mode_t +{ + MODE_UNDEFINED = 0, + MODE_TFTILI_320x240 = 1, + MODE_TFTST_320x240 = 2, + MODE_VGA_320x240 = 3, + MODE_VGA_320x480 = 4, + MODE_VGA_352x240 = 5, + MODE_VGA_352x480 = 6, + MODE_VGA_512x240 = 7, + MODE_VGA_512x480 = 8, + MODE_VGA_640x240 = 9, + MODE_VGA_640x480 = 10 +} gfx_mode_t; + +typedef enum gfx_error_t +{ + GFX_OK = 0, + GFX_ERROR = -1 +} gfx_error_t; + + +#ifdef __cplusplus + +class T4_DSP +{ + public: + T4_DSP(); + + gfx_error_t begin(gfx_mode_t mode); + gfx_mode_t getMode(void); + void startRefresh(void); + void stopRefresh(); + + int get_frame_buffer_size(int *width, int *height); + void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); + + // wait next Vsync + void waitSync(); + void waitLine(int line); + + // NoDMA functions + void fillScreenNoDma(uint16_t color); + void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + // DMA functions + void fillScreen(uint16_t color); + void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + void writeLine(int width, int height, int y, uint16_t *buf); + void writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + void writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16); + void writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + + protected: + static uint8_t _rst, _cs, _dc; + static uint8_t _mosi, _sclk; + static uint8_t _vsync_pin; + static DMAChannel flexio1DMA; + static DMAChannel flexio2DMA; + void tft_setup(bool isST); + static void TFT_isr(void); + static void QT3_isr(void); +}; + +#endif +#endif diff --git a/MCUME_teensy41/teensy64/teensy64.ino b/MCUME_teensy41/teensy64/teensy64.ino index 3c84070..00388a0 100644 --- a/MCUME_teensy41/teensy64/teensy64.ino +++ b/MCUME_teensy41/teensy64/teensy64.ino @@ -3,134 +3,20 @@ extern "C" { #include "iopins.h" } -#include "c64.h" - -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -TFT_T_DMA tft; -#else -#include "tft_t_dma.h" -TFT_T_DMA tft = TFT_T_DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, TFT_TOUCH_CS, TFT_TOUCH_INT); -#endif - -bool vgaMode = false; - -static unsigned char palette8[PALETTE_SIZE]; -static unsigned short palette16[PALETTE_SIZE]; -static IntervalTimer myTimer; -volatile boolean vbl=true; -static int skip=0; -static elapsedMicros tius; - -static void vblCount() { - if (vbl) { - vbl = false; - } else { - vbl = true; - } -} - -void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) -{ - if (index>8, - 320 & 0xFF, // YEND = 320 - ST7735_INVON , DELAY, // 7: hack - 10, - ST7735_NORON , DELAY, // 8: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 9: Main screen turn on, no args, w/delay - 255 -#endif -}; - -static void dmaInterrupt() { - dmatx.clearInterrupt(); - curTransfer++; - if (curTransfer >= nbTransfer) { - curTransfer = 0; - if (cancelled) { - dmatx.disable(); - rstop = 1; - } - } - arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2); -} - -static void setDmaStruct() { - uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; - int i=0; - uint16_t col=RGBVAL16(0x00,0x00,0x00);; - while (remaining > 0) { - uint16_t * fb = blocks[i]; - int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining); -#ifdef TFT_DEBUG - Serial.println((unsigned long)blocks[i]); - Serial.println(remaining); -#endif - switch (i) { - case 0: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb0[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0x00); -#endif - break; - case 1: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb1[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0xff); -#endif - break; - case 2: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb2[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0x00,0xff); -#endif - break; - case 3: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb3[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0xff,0x00,0xff); -#endif - break; - } - blocks[i] = fb; - if (blocks[i] == 0) { - Serial.print("ILI9341 allocaltion failed for block "); - Serial.println(i); - delay(10000); - } - - for (int j=0;jATTR_DST = 1; - dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); - dmasettings[i].interruptAtCompletion(); - remaining -= len; - i++; - } - dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); - nbTransfer = i; -#ifdef TFT_DEBUG - Serial.println(nbTransfer); -#endif -} - - -TFT_T_DMA::TFT_T_DMA(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso, uint8_t touch_cs, uint8_t touch_irq) -{ - _cs = cs; - _dc = dc; - _rst = rst; - _mosi = mosi; - _sclk = sclk; - _miso = miso; - pinMode(_dc, OUTPUT); - pinMode(_cs, OUTPUT); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); - if ( (touch_cs != 255) && (touch_irq != 255) ) { - _touch_irq = touch_irq; - _touch_cs = touch_cs; - pinMode(_touch_cs, OUTPUT); - pinMode(touch_irq, INPUT_PULLUP); - digitalWrite(_touch_cs, 1); - } -} - - -void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { - int dx=0; - int dy=0; -#ifdef ST7789 - if (TFT_REALWIDTH == TFT_REALHEIGHT) - { -#ifdef ROTATE_SCREEN - if (!flipped) { - dy += 80; - } -#else - if (flipped) { - dx += 80; - } -#endif - } -#endif - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - SPI.transfer16(x1+dx); - digitalWrite(_dc, 1); - SPI.transfer16(x2+dx); - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - digitalWrite(_dc, 1); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - return; - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - - SPI.transfer16(x1+dx); - SPI.transfer16(x2+dx); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - -void TFT_T_DMA::begin(void) { - SPI.setMOSI(_mosi); - SPI.setMISO(_miso); - SPI.setSCK(_sclk); - SPI.begin(); - - // Initialize display - if (_rst != 0xff) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - const uint8_t *addr = init_commands; - digitalWrite(_cs, 0); -#ifdef ILI9341 - while (1) { - uint8_t count = *addr++; - if (count-- == 0) break; - - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - - while (count-- > 0) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - } - - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(ILI9341_DISPON); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); -#endif -#ifdef ST7789 - uint8_t numCommands, numArgs; - uint16_t ms; - numCommands = *addr++; // Number of commands to follow - while(numCommands--) { // For each command... - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - numArgs = *addr++; // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs > 1) { // For each argument... - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - numArgs--; - } - - if (numArgs) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - if(ms) { - ms = *addr++; // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - digitalWrite(_cs, 1); - SPI.endTransaction(); - delay(ms); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - } - } - digitalWrite(_cs, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - SPI.endTransaction(); - - cancelled = false; - -#ifdef FLIP_SCREEN - flipscreen(true); -#else - flipscreen(false); -#endif -#ifdef ST7789 - if (TFT_REALWIDTH != TFT_REALHEIGHT) - { - flipscreen(true); - } -#endif -}; - - - -void TFT_T_DMA::flipscreen(bool flip) -{ - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(TFT_MADCTL); - digitalWrite(_dc, 1); - if (flip) { - flipped=true; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB); -#endif -#endif - } - else { - flipped=false; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB); -#endif -#endif - } - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - -boolean TFT_T_DMA::isflipped(void) -{ - return(flipped); -} - - -#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) - - -void TFT_T_DMA::startDMA(void) { - curTransfer = 0; - rstop = 0; - //dmatx.begin(true); - dmatx.attachInterrupt(dmaInterrupt); - setDmaStruct(); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - - digitalWrite(_cs, HIGH); - SPI.begin(); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); - - - LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: - LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX - LPSPIP_TCR = 15; // Framesize 16 Bits - //LPSPIP_FCR = 0; // Fifo Watermark - LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable - LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: - dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); - - dmatx = dmasettings[0]; - digitalWrite(_cs, 0); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - dmatx.enable(); -} - - -void TFT_T_DMA::stopDMA(void) { - rstop = 0; - wait(); - delay(50); - cancelled = false; - dmatx.detachInterrupt(); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - SPI.end(); -#ifdef ST7789 - begin(); -#endif -#ifdef ILI9341 - SPI.begin(); - digitalWrite(_cs, 0); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - SPI.endTransaction(); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); -} - -void TFT_T_DMA::wait(void) { - rstop = 1; - unsigned long m = millis(); - cancelled = true; - while (!rstop) { - if ((millis() - m) > 100) break; - delay(10); - asm volatile("wfi"); - }; - rstop = 0; -} - -int TFT_T_DMA::get_frame_buffer_size(int *width, int *height, int *stride){ - if (width != nullptr) *width = TFT_REALWIDTH; - if (height != nullptr) *height = TFT_REALHEIGHT; - if (stride != nullptr) *stride = TFT_REALWIDTH; - return TFT_REALWIDTH; -} - - -/*********************************************************************************************** - Touch functions - ***********************************************************************************************/ -/* Code based on ... - * - * @file XPT2046.cpp - * @date 19.02.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the XPT2046 driver for Arduino. - */ - -#define ADC_MAX 0x0fff - -void TFT_T_DMA::enableTouchIrq() -{ - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 }; - SPI.transfer((void*)&buf[0],3); - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); -} - -//Default callibration for non flipped -#define TX_MIN 30 -#define TY_MIN 20 -#define TX_MAX 300 -#define TY_MAX 220 - -//Default callibration for flipped -#define TFX_MIN 20 -#define TFY_MIN 25 -#define TFX_MAX 288 -#define TFY_MAX 221 - -static uint16_t txMin; -static uint16_t tyMin; -static uint16_t txMax; -static uint16_t tyMax; - - -void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { - if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) { - txMin = xMin; - tyMin = yMin; - txMax = xMax; - tyMax = yMax; - } - else { - if (flipped) { - txMin = TFX_MIN; - tyMin = TFY_MIN; - txMax = TFX_MAX; - tyMax = TFY_MAX; - } - else { - txMin = TX_MIN; - tyMin = TY_MIN; - txMax = TX_MAX; - tyMax = TY_MAX; - } - } -} - - -void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - if ( TOUCH_ENABLED() ) { - uint16_t x = 0; - uint16_t y = 0; - uint16_t z1 = 0; - uint16_t z2 = 0; - uint8_t i = 0; - int16_t xraw=0, yraw=0; - - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - - for(; i < 15; i++) { - // SPI requirer 32bit aliment - uint8_t buf[12] = { - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00 - }; - SPI.transfer(&buf[0], &buf[0], 12); - y += (buf[1] << 8 | buf[2])>>3; - x += (buf[4] << 8 | buf[5])>>3; - z1 += (buf[7] << 8 | buf[8])>>3; - z2 += (buf[10] << 8 | buf[11])>>3; - } - enableTouchIrq(); - - if(i == 0) { - *oX = 0; - *oY = 0; - *oZ = 0; - } - else { - x /= i; - y /= i; - z1 /= i; - z2 /= i; - } - - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); - int z = z1 + ADC_MAX - z2; - if (flipped) { - xraw = x; - yraw = y; - } else { - xraw = ADC_MAX - x; - yraw = ADC_MAX - y; - } - xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1); - yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1); - - *oX = xraw; - *oY = yraw; - *oZ = z; - } - else - { - *oX = 0; - *oY = 0; - *oZ = 0; - } -} - -void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - readRaw(oX,oY,oZ); - // callibrate ... - if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin); - if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin); - //Serial.print(*oX); - //Serial.print(" "); - //Serial.println(*oY); -} - - -/*********************************************************************************************** - No DMA functions - ***********************************************************************************************/ -void TFT_T_DMA::fillScreenNoDma(uint16_t color) { - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - int i,j; - for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(arx, ary, arx+arw-1, ary+arh-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - bits = *charpt++; - //digitalWrite(_dc, 1); - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - x +=8; -#ifdef ILI9341 - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); -#endif - digitalWrite(_cs, 1); - SPI.endTransaction(); - } - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - - - -/*********************************************************************************************** - DMA functions - ***********************************************************************************************/ -uint16_t * TFT_T_DMA::getLineBuffer(int j) -{ - uint16_t * block=blocks[j>>6]; - return(&block[(j&0x3F)*TFT_REALWIDTH]); -} - -void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) { - uint8_t *buffer=buf; - uint8_t *src; - - int i,j,y=0; - if (width*2 <= TFT_REALWIDTH) { - for (j=0; j>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH]; - for (i=0; i>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x]; - for (i=0; i>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - block=blocks[l>>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt++; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - x +=8; - } -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { - drawSprite(x,y,bitmap, 0,0,0,0); -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) -{ - int bmp_offx = 0; - int bmp_offy = 0; - uint16_t *bmp_ptr; - - int w =*bitmap++; - int h = *bitmap++; - - - if ( (arw == 0) || (arh == 0) ) { - // no crop window - arx = x; - ary = y; - arw = w; - arh = h; - } - else { - if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - int l=ary; - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx]; - bmp_ptr = (uint16_t*)bitmap; - for (int col=0;col -#include -#include -#endif - -#include "tft_t_dma_config.h" - -#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) -#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define R16(rgb) ((rgb>>8)&0xf8) -#define G16(rgb) ((rgb>>3)&0xfc) -#define B16(rgb) ((rgb<<3)&0xf8) - -#define PAL_COLOR_MASK 0xff - -#ifdef LOHRES -#define TFT_WIDTH 240 -#define TFT_REALWIDTH 240 -#else -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 -#endif -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - -//#define WIDTH 272 -//#define HEIGHT 228 - -#define LINES_PER_BLOCK 64 -#define NR_OF_BLOCK 4 -#define SCREEN_DMA_NUM_SETTINGS NR_OF_BLOCK - - -#ifdef ILI9341 - -#define ILI9341_NOP 0x00 -#define ILI9341_SWRESET 0x01 -#define ILI9341_RDDID 0x04 -#define ILI9341_RDDST 0x09 - -#define ILI9341_SLPIN 0x10 -#define ILI9341_SLPOUT 0x11 -#define ILI9341_PTLON 0x12 -#define ILI9341_NORON 0x13 - -#define ILI9341_RDMODE 0x0A -#define ILI9341_RDMADCTL 0x0B -#define ILI9341_RDPIXFMT 0x0C -#define ILI9341_RDIMGFMT 0x0D -#define ILI9341_RDSELFDIAG 0x0F - -#define ILI9341_INVOFF 0x20 -#define ILI9341_INVON 0x21 -#define ILI9341_GAMMASET 0x26 -#define ILI9341_DISPOFF 0x28 -#define ILI9341_DISPON 0x29 - -#define ILI9341_CASET 0x2A -#define ILI9341_PASET 0x2B -#define ILI9341_RAMWR 0x2C -#define ILI9341_RAMRD 0x2E - -#define ILI9341_PTLAR 0x30 -#define ILI9341_MADCTL 0x36 -#define ILI9341_VSCRSADD 0x37 -#define ILI9341_PIXFMT 0x3A - -#define ILI9341_FRMCTR1 0xB1 -#define ILI9341_FRMCTR2 0xB2 -#define ILI9341_FRMCTR3 0xB3 -#define ILI9341_INVCTR 0xB4 -#define ILI9341_DFUNCTR 0xB6 - -#define ILI9341_PWCTR1 0xC0 -#define ILI9341_PWCTR2 0xC1 -#define ILI9341_PWCTR3 0xC2 -#define ILI9341_PWCTR4 0xC3 -#define ILI9341_PWCTR5 0xC4 -#define ILI9341_VMCTR1 0xC5 -#define ILI9341_VMCTR2 0xC7 - -#define ILI9341_RDID1 0xDA -#define ILI9341_RDID2 0xDB -#define ILI9341_RDID3 0xDC -#define ILI9341_RDID4 0xDD - -#define ILI9341_GMCTRP1 0xE0 -#define ILI9341_GMCTRN1 0xE1 - -#define ILI9341_MADCTL_MY 0x80 -#define ILI9341_MADCTL_MX 0x40 -#define ILI9341_MADCTL_MV 0x20 -#define ILI9341_MADCTL_ML 0x10 -#define ILI9341_MADCTL_RGB 0x00 -#define ILI9341_MADCTL_BGR 0x08 -#define ILI9341_MADCTL_MH 0x04 - -#define TFT_CASET ILI9341_CASET -#define TFT_PASET ILI9341_PASET -#define TFT_RAMWR ILI9341_RAMWR -#define TFT_MADCTL ILI9341_MADCTL - -#endif - - -#ifdef ST7789 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_RGB 0x00 -#define ST77XX_MADCTL_BGR 0x08 -#define ST77XX_MADCTL_MH 0x04 - -#define TFT_CASET ST7735_CASET -#define TFT_PASET ST7735_RASET -#define TFT_RAMWR ST7735_RAMWR -#define TFT_MADCTL ST7735_MADCTL - -#endif - - - -#ifdef __cplusplus - -class TFT_T_DMA -{ - public: - TFT_T_DMA(uint8_t _CS, uint8_t _DC, uint8_t _RST = 255, uint8_t _MOSI=11, uint8_t _SCLK=13, uint8_t _MISO=12, uint8_t touch_cs=38, uint8_t touch_irq=37); - - void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); - void begin(void); - void flipscreen(bool flip); - boolean isflipped(void); - void startDMA(void); - void stopDMA(); - int get_frame_buffer_size(int *width, int *height, int *stride); - - // Touch screen functions - #define TOUCH_ENABLED() ((_touch_cs != 255) && (_touch_irq != 255)) - bool isTouching(void) { return ((!TOUCH_ENABLED())?false:(digitalRead(_touch_irq) == LOW)); } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax); - - // NoDMA functions - void writeScreenNoDma(const uint16_t *pcolors); - void fillScreenNoDma(uint16_t color); - void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - // DMA functions - uint16_t * getLineBuffer(int j); - void writeScreen(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int y, uint16_t *buf); - void fillScreen(uint16_t color); - void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - protected: - uint8_t _rst, _cs, _dc; - uint8_t _miso, _mosi, _sclk; - uint8_t _touch_irq=255, _touch_cs=255; - bool flipped=false; - - void wait(void); - void enableTouchIrq(); -}; - -#endif -#endif diff --git a/MCUME_teensy41/teensy64/tft_t_dma_config.h b/MCUME_teensy41/teensy64/tft_t_dma_config.h deleted file mode 100644 index 354cf74..0000000 --- a/MCUME_teensy41/teensy64/tft_t_dma_config.h +++ /dev/null @@ -1,14 +0,0 @@ -#include "platform_config.h" - -//#define ST7789 1 -//#define ILI9341 1 - -#define TFT_LINEARINT 1 -#define LINEARINT_HACK 1 - -//#define FLIP_SCREEN 1 -//#define TFT_DEBUG 1 -#if defined(__IMXRT1052__) || defined(__IMXRT1062__) -//#define TFT_STATICFB 1 -#endif - diff --git a/MCUME_teensy41/teensy64/util.cpp b/MCUME_teensy41/teensy64/timerutil.cpp old mode 100755 new mode 100644 similarity index 98% rename from MCUME_teensy41/teensy64/util.cpp rename to MCUME_teensy41/teensy64/timerutil.cpp index 5eaf921..6c63f98 --- a/MCUME_teensy41/teensy64/util.cpp +++ b/MCUME_teensy41/teensy64/timerutil.cpp @@ -34,7 +34,7 @@ Copyright Frank Bösing, 2017 */ #include #include -#include "util.h" +#include "timerutil.h" //Attention, don't use WFI-instruction - the CPU does not count cycles during sleep void enableCycleCounter(void) { @@ -68,4 +68,4 @@ void setAudioOn(void) { void listInterrupts() { -} \ No newline at end of file +} diff --git a/MCUME_teensy41/teensy64/util.h b/MCUME_teensy41/teensy64/timerutil.h similarity index 100% rename from MCUME_teensy41/teensy64/util.h rename to MCUME_teensy41/teensy64/timerutil.h diff --git a/MCUME_teensy41/teensy64/vga_t_dma.h b/MCUME_teensy41/teensy64/vga_t_dma.h deleted file mode 100644 index 81a986b..0000000 --- a/MCUME_teensy41/teensy64/vga_t_dma.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - Wrapping class to extend VGA_T4 to TFT_T_DMA -*/ - -#ifndef _VGA_T_DMAH_ -#define _VGA_T_DMAH_ - -#ifdef __cplusplus -#include -#endif - - -#define RGBVAL16(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) - - - - -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 - -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - - - -#ifdef __cplusplus - -class TFT_T_DMA: public VGA_T4 -{ - public: - // Fake touch screen functions - bool isTouching(void) { return false; } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { } - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { }; - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { } - - // fake DMA functions - void startDMA(void) { }; - void stopDMA(void) { }; - - // fake no DMA functions - void writeScreenNoDma(const vga_pixel *pcolors) { writeScreen(pcolors); } - void fillScreenNoDma(vga_pixel color) { clear(color); } - void drawTextNoDma(int16_t x, int16_t y, const char * text, vga_pixel fgcolor, vga_pixel bgcolor, bool doublesize) { drawText(x,y,text,fgcolor,bgcolor,doublesize); } - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, vga_pixel color) { drawRect(x, y, w, h, color); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap) { drawSprite(x, y, bitmap); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh) { drawSprite(x, y, bitmap, croparx, cropary, croparw, croparh); } -}; - - -#endif -#endif diff --git a/MCUME_teensy41/teensy64/vic.cpp b/MCUME_teensy41/teensy64/vic.cpp index 5f1af86..2584174 100644 --- a/MCUME_teensy41/teensy64/vic.cpp +++ b/MCUME_teensy41/teensy64/vic.cpp @@ -69,11 +69,7 @@ #define BORDER_LEFT 0 #define BORDER_RIGHT 0 -#ifdef HAS_T4_VGA -typedef uint8_t tpixel; -#else typedef uint16_t tpixel; -#endif #define MAXCYCLESSPRITES0_2 3 #define MAXCYCLESSPRITES3_7 5 @@ -1606,12 +1602,7 @@ g-Zugriff } - -#ifdef HAS_T4_VGA - emu_DrawLine8(&linebuffer[0], SCREEN_WIDTH, SCREEN_HEIGHT, (r - FIRSTDISPLAYLINE)); -#else emu_DrawLine16(&linebuffer[0], SCREEN_WIDTH, SCREEN_HEIGHT, (r - FIRSTDISPLAYLINE)); -#endif diff --git a/MCUME_teensy41/teensy64/c64.cpp b/MCUME_teensy41/teensy64/wrapemu.cpp similarity index 98% rename from MCUME_teensy41/teensy64/c64.cpp rename to MCUME_teensy41/teensy64/wrapemu.cpp index 007af18..1f93d92 100644 --- a/MCUME_teensy41/teensy64/c64.cpp +++ b/MCUME_teensy41/teensy64/wrapemu.cpp @@ -198,14 +198,14 @@ uint8_t cia1PORTA(void) { if (keys & MASK_JOY2_BTN) v &= 0xEF; if (keys & MASK_JOY2_UP) v &= 0xFE; if (keys & MASK_JOY2_DOWN) v &= 0xFD; - if (keys & MASK_JOY2_RIGHT) v &= 0xFB; - if (keys & MASK_JOY2_LEFT) v &= 0xF7; + if (keys & MASK_JOY2_LEFT) v &= 0xFB; + if (keys & MASK_JOY2_RIGHT) v &= 0xF7; } else { if (keys & MASK_JOY1_BTN) v &= 0xEF; if (keys & MASK_JOY1_UP) v &= 0xFE; if (keys & MASK_JOY1_DOWN) v &= 0xFD; - if (keys & MASK_JOY1_RIGHT) v &= 0xFB; - if (keys & MASK_JOY1_LEFT) v &= 0xF7; + if (keys & MASK_JOY1_LEFT) v &= 0xFB; + if (keys & MASK_JOY1_RIGHT) v &= 0xF7; } if (!kbdData.kv) return v; //Keine Taste gedrückt diff --git a/MCUME_teensy41/teensy64/c64.h b/MCUME_teensy41/teensy64/wrapemu.h similarity index 100% rename from MCUME_teensy41/teensy64/c64.h rename to MCUME_teensy41/teensy64/wrapemu.h diff --git a/MCUME_teensy41/teensy800/antic.c b/MCUME_teensy41/teensy800/antic.c index 542f5fa..843d3eb 100644 --- a/MCUME_teensy41/teensy800/antic.c +++ b/MCUME_teensy41/teensy800/antic.c @@ -41,7 +41,7 @@ UWORD Screen_atari[ATARI_WIDTH / 2]; // = NULL; #define DRAWLINE() \ if ( (ANTIC_ypos > 8) && (ANTIC_ypos < 248)) { \ - emu_DrawLine((unsigned char *)&Screen_atari[32/sizeof(Screen_atari[0])], 320, 240, ANTIC_ypos-8); \ + emu_DrawLinePal16((unsigned char *)&Screen_atari[32/sizeof(Screen_atari[0])], 320, 240, ANTIC_ypos-8); \ } diff --git a/MCUME_teensy41/teensy800/emuapi.cpp b/MCUME_teensy41/teensy800/emuapi.cpp index eb4be06..e128cca 100644 --- a/MCUME_teensy41/teensy800/emuapi.cpp +++ b/MCUME_teensy41/teensy800/emuapi.cpp @@ -5,25 +5,31 @@ extern "C" { #include "iopins.h" } -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#else -#include "tft_t_dma.h" -#endif +#include -#ifdef HAS_USBKEY +#ifdef HAS_USB #include "USBHost_t36.h" // Read this header first for key info USBHost myusb; USBHub hub1(myusb); +#ifdef HAS_USBKEY KeyboardController keyboard1(myusb); USBHIDParser hid1(myusb); MouseController mouse1(myusb); +#endif +#ifdef HAS_USBMIDI MIDIDevice midi1(myusb); #endif +#ifdef HAS_USBJOY +#define COUNT_JOYSTICKS 4 +JoystickController joysticks[COUNT_JOYSTICKS](myusb); +#endif +#endif static bool emu_writeConfig(void); static bool emu_readConfig(void); static bool emu_eraseConfig(void); +static bool emu_writeGfxConfig(char * display_type); +static int emu_readGfxConfig(void); static bool mouseDetected = false; static bool keyboardDetected = false; @@ -34,8 +40,9 @@ static File file; #define MAX_FILES 64 #define AUTORUN_FILENAME "autorun.txt" +#define GFX_CFG_FILENAME "gfxmode.txt" -#define MAX_FILENAME_SIZE 24 +#define MAX_FILENAME_SIZE 34 #define MAX_MENULINES 9 #define TEXT_HEIGHT 16 #define TEXT_WIDTH 8 @@ -53,7 +60,8 @@ static File file; #define MENU_VGA_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) #define MENU_VGA_YOFFSET (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37) -extern TFT_T_DMA tft; +#include "t4_dsp.h" +T4_DSP tft; static int nbFiles=0; static int curFile=0; @@ -65,6 +73,8 @@ static char selected_filename[MAX_FILENAME_SIZE]=""; static char second_selected_filename[MAX_FILENAME_SIZE]=""; static bool menuRedraw=true; static bool autorun=false; +static bool vgahires=false; + static const unsigned short * keys; #ifdef TEECOMPUTER @@ -103,7 +113,7 @@ void emu_printf(int val) void emu_printi(int val) { - Serial.println(val); + Serial.println(val,HEX); } void emu_printh(int val) @@ -158,6 +168,29 @@ void emu_Free(void * pt) free(pt); } +#define SMEMPOOL (0x800000) +EXTMEM static unsigned char slowmem[SMEMPOOL]; +static int slowmempt = 0; + +void * emu_SMalloc(unsigned int size) +{ + void * mem = (void*)&slowmem[slowmempt]; + slowmempt += size; + + if ( slowmempt > SMEMPOOL ) { + mem = NULL; + emu_printf("failure to allocate slow"); + } + else { + emu_printf("could allocate slow static "); + emu_printf(size); + } + return mem; +} + +void emu_SFree(void * pt) +{ +} /******************************** * Input and keyboard ********************************/ @@ -329,6 +362,12 @@ int emu_ReadKeys(void) #endif if ( row & 0x02 ) retval |= MASK_JOY2_BTN; + +#ifdef EXTPAD + if ( sh_pressed ) retval |= MASK_KEY_USER3; + if ( fn_pressed ) retval |= MASK_KEY_USER1; + digitalWrite(KLED, 0); +#else // Handle LED flash uint32_t time_ms=millis(); if ((time_ms-last_t_ms) > 100) { @@ -412,8 +451,9 @@ int emu_ReadKeys(void) if ( key_fn ) retval |= MASK_KEY_USER2; if ( ( key_fn ) && (keymatrix[4] == 0x10 )) retval |= MASK_KEY_USER1; +#endif - if ( (key_fn) && (key_sh) ) + if ( (fn_pressed) && (sh_pressed) ) #else if ( ((retval & (MASK_KEY_USER1+MASK_KEY_USER2)) == (MASK_KEY_USER1+MASK_KEY_USER2)) || (retval & MASK_KEY_USER4 ) ) @@ -453,8 +493,10 @@ int emu_ReadKeys(void) while (true) { ; } -#endif +#endif } + + emu_GetJoystick(); return (retval); } @@ -607,7 +649,7 @@ int emu_setKeymap(int index) { } int emu_GetMouse(int *x, int *y, int *buts) { -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBKEY) if (mouse1.available()) { *buts = mouse1.getButtons(); *x = mouse1.getMouseX(); @@ -620,7 +662,23 @@ int emu_GetMouse(int *x, int *y, int *buts) { return 0; } -#ifdef HAS_USBKEY +int emu_GetJoystick(void) { +#if defined(HAS_USB) && (HAS_USBJOY) + for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) { + if (joysticks[joystick_index].available()) { + uint64_t axis_mask = joysticks[joystick_index].axisMask(); + uint64_t axis_changed_mask = joysticks[joystick_index].axisChangedMask(); + uint32_t buttons = joysticks[joystick_index].getButtons(); + Serial.printf("Joystick(%d): buttons = %x", joystick_index, buttons); + Serial.println(); + } + } + return 1; +#endif + return 0; +} + +#if defined(HAS_USB) && (HAS_USBKEY) void OnPress(auto key) { keyboardDetected = true; @@ -764,7 +822,7 @@ int emu_KeyboardDetected(void) { return (keyboardDetected?1:0); } -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) static unsigned char midiBuffer[16]; static unsigned char midiLastCmd=0; static int midiDataCnt=0; @@ -772,8 +830,7 @@ static int midiCmdNbParam=0; #endif void emu_MidiOnDataReceived(unsigned char value) { - -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) //Serial.println(value, HEX); //10000000 = 128 = note off //10010000 = 144 = note on @@ -941,6 +998,7 @@ void emu_MidiOnDataReceived(unsigned char value) { /******************************** * Menu file loader UI ********************************/ +#ifdef FILEBROWSER static int readNbFiles(void) { int totalFiles = 0; @@ -970,8 +1028,6 @@ static int readNbFiles(void) { return totalFiles; } - - void backgroundMenu(void) { menuRedraw=true; tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00)); @@ -981,11 +1037,13 @@ void backgroundMenu(void) { int handleMenu(uint16_t bClick) { if (autorun) { + toggleMenu(false); + menuRedraw=false; return (ACTION_RUN1); } int action = ACTION_NONE; - if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) ) { + if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) || ( bClick & MASK_KEY_USER2 ) ) { char newpath[MAX_FILENAME_PATH]; strcpy(newpath, selection); strcat(newpath, "/"); @@ -996,17 +1054,31 @@ int handleMenu(uint16_t bClick) File file = SD.open(selection); if (file.isDirectory()) { curFile = 0; - nbFiles = readNbFiles(); + nbFiles = readNbFiles(); + menuRedraw=true; } - else { - action = ACTION_RUN1; + else + { #ifdef TEECOMPUTER - if (key_extmode) { + if ( (key_extmode) || ( key_sh) ) { emu_writeConfig(); } + if ( tft.getMode() < MODE_VGA_320x240) { + if ( bClick & MASK_KEY_USER2 ) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + } + //emu_SwapJoysticks(0); #endif + toggleMenu(false); + menuRedraw=false; + return (ACTION_RUN1); } - menuRedraw=true; } else if ( bClick & MASK_KEY_USER1 ) { menuRedraw=true; @@ -1015,19 +1087,14 @@ int handleMenu(uint16_t bClick) strcat(second_selection, "/"); strcat(second_selection, second_selected_filename); action = ACTION_RUN2; - } - else if ( bClick & MASK_KEY_USER2 ) { - menuRedraw=true; - //action = ACTION_RUN3; - emu_SwapJoysticks(0); - } + } else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) { if (curFile!=0) { menuRedraw=true; curFile--; } } - else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { + else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { if ((curFile-9)>=0) { menuRedraw=true; curFile -= 9; @@ -1042,7 +1109,7 @@ int handleMenu(uint16_t bClick) menuRedraw=true; } } - else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { + else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { if ((curFile<(nbFiles-9)) && (nbFiles)) { curFile += 9; menuRedraw=true; @@ -1099,12 +1166,12 @@ int handleMenu(uint16_t bClick) return (action); } -bool menuActive(void) +int menuActive(void) { - return (menuOn); + return (menuOn?1:0); } -void toggleMenu(bool on) { +void toggleMenu(int on) { if (on) { menuOn=true; backgroundMenu(); @@ -1122,7 +1189,7 @@ char * menuSecondSelection(void) { return (second_selection); } - +#endif /******************************** * OSKB handling @@ -1140,8 +1207,9 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) char c[4] = {' ',0,' ',0}; const char * cpt = str; int i=0; - int fb_width,fb_height; - tft.get_frame_buffer_size(&fb_width, &fb_height); + int fb_width,fb_height,fbstride; + + fbstride = tft.get_frame_buffer_size(&fb_width, &fb_height); int ypos = (bottom?(fb_height-2*8):0); int line = row + (bottom?2:0); while ((c[1] = *cpt++)) @@ -1150,7 +1218,7 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0); else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff); if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff); - tft.drawTextNoDma(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); + tft.drawText(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); i++; } } @@ -1248,7 +1316,7 @@ int handleOSKB(void) { return retval; } -void toggleOSKB(bool forceon) { +void toggleOSKB(int forceon) { if (forceon) { oskbOn = true; drawOSKB(); @@ -1332,6 +1400,17 @@ int emu_FileRead(void * buf, int size, int handler) #endif } +int emu_FileWrite(void * buf, int size, int handler) +{ +// emu_printf("emu_FileWrite"); +// emu_printi(handler); +#ifdef HCFH + return (file.write(buf, size)); +#else + return (getFileHandler(handler).write(buf, size)); +#endif +} + int emu_FileGetc(int handler) { // emu_printf("FileGetc"); // emu_printi(handler); @@ -1404,6 +1483,9 @@ unsigned int emu_FileSize(const char * filepath) emu_printf(filesize); lofile.close(); } + else { + emu_printf("filesize failed"); + } return(filesize); } @@ -1489,6 +1571,48 @@ static bool emu_eraseConfig(void) SD.remove (ROMSDIR "/" AUTORUN_FILENAME); } +static bool emu_writeGfxConfig(char * display_type) +{ + bool retval = false; + SD.remove ("/" GFX_CFG_FILENAME); + if (strcmp(display_type, "VGA")) { + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(display_type, strlen(display_type)) != strlen(display_type)) { + emu_printf("GFX config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + } + return retval; +} + +#define CFG_VGA 0 +#define CFG_ILI 1 +#define CFG_ST 2 + +static int emu_readGfxConfig(void) +{ + int retval = CFG_VGA; // No file = VGA + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + if (filesize == 2) // "ST" + { + retval = CFG_ST; + } + else if (filesize == 3) // "ILI" + { + retval = CFG_ILI; + } + lofile.close(); + } + return retval; +} + /******************************** * File IO compatibility ********************************/ @@ -1670,62 +1794,249 @@ FRESULT f_mkdir (const char* path) /******************************** - * Initialization + * GFX wrapper ********************************/ -void emu_init(void) +static unsigned short palette16[PALETTE_SIZE]; +static IntervalTimer myTimer; +volatile boolean vbl=true; +volatile boolean vgatimervsync=false; +static void (*vblCallback)(void) = nullptr; +static int skip=0; + +static void vblCount() { + if (vbl) { + vbl = false; + } else { + vbl = true; + } +} + +void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) +{ + if (index= MODE_VGA_320x240 ) { + if (vgatimervsync) { + while (vbl==vb) {}; + } + else { + tft.waitSync(); + } + } + else { + while (vbl==vb) {}; + } + if (vblCallback != nullptr) { + vblCallback(); + } +} + +void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride) +{ + if (skip == 0) { + tft.writeScreenPal(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); + } +} +void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLinePal(width,height,line, VBuf, palette16); + } +} + +void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine(width,height,line, VBuf); + } +} + +void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine8(width,height,line, VBuf, palette16); + } +} + +int emu_IsVga(void) +{ + return (tft.getMode() >= MODE_VGA_320x240?1:0); +} + +int emu_IsVgaHires(void) +{ + return (tft.getMode() >= MODE_VGA_640x240?1:0); +} + +int emu_FrameSkip(void) +{ + return skip; +} + + +/******************************** + * AUDIO wrapper +********************************/ +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +AudioPlaySystem mymixer; + +void emu_sndInit() { + Serial.println("sound init"); + mymixer.begin_audio(256, mymixer.snd_Mixer); + mymixer.start(); +} + +void emu_sndPlaySound(int chan, int volume, int freq) +{ + if (chan < 6) { + mymixer.sound(chan, freq, volume); + } + /* + Serial.print(chan); + Serial.print(":" ); + Serial.print(volume); + Serial.print(":" ); + Serial.println(freq); + */ +} + +void emu_sndPlayBuzz(int size, int val) { + mymixer.buzz(size,val); + //Serial.print((val==1)?1:0); + //Serial.print(":"); + //Serial.println(size); +} +#endif + +/******************************** + * Initialization +********************************/ +void emu_init(int hires) { Serial.begin(115200); + vgahires = hires; -#ifdef HAS_USBKEY +#ifdef HAS_USB myusb.begin(); +#ifdef HAS_USBKEY keyboard1.attachPress(OnPress); keyboard1.attachRelease(OnRelease); #endif +#endif - while (!SD.begin(SD_CS)) +#ifdef FILEBROWSER + if (!SD.begin(SD_CS)) { - Serial.println("SD begin failed, retrying..."); - delay(1000); + Serial.println("No SD card detected"); } strcpy(selection,ROMSDIR); - FileHandlersInit(); - nbFiles = readNbFiles(); - - Serial.print("SD initialized, files found: "); Serial.println(nbFiles); +#endif emu_InitJoysticks(); #ifdef SWAP_JOYSTICK - joySwapped = true; + joySwapped = true; #else - joySwapped = false; + joySwapped = false; #endif -#ifdef TEECOMPUTER -#ifndef HAS_T4_VGA - tft.flipscreen(false); -#endif -#endif int keypressed = emu_ReadKeys(); +#ifdef HAS_T4_VGA + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } +#else + int gfx_mode = CFG_VGA; // default +#ifdef FILEBROWSER + gfx_mode = emu_readGfxConfig(); +#endif + // Force VGA if UP pressed + if (keypressed & MASK_JOY2_UP) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("VGA"); +#endif + gfx_mode = CFG_VGA; + } + else { + if (keypressed & MASK_JOY2_LEFT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ST"); +#endif + gfx_mode = CFG_ST; + } + else if (keypressed & MASK_JOY2_RIGHT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ILI"); +#endif + gfx_mode = CFG_ILI; + } + } + if (gfx_mode == CFG_VGA) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + else + { + tft.begin(gfx_mode == CFG_ILI?MODE_TFTILI_320x240:MODE_TFTST_320x240); + } +#endif + if (keypressed & MASK_JOY2_DOWN) { tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) ); tft.drawTextNoDma(64,48, (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); +#ifdef FILEBROWSER emu_eraseConfig(); delay(1000); +#endif } else { +#ifdef FILEBROWSER if (emu_readConfig()) { autorun = true; } +#endif } +#ifdef FILEBROWSER toggleMenu(true); +#endif } -void emu_start(void) +void emu_start(int vblms, void * callback, int forcetimervsync) { + vgatimervsync = forcetimervsync?true:false; + tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); + tft.startRefresh(); + if (callback != nullptr) { + vblCallback = callback; + } + + myTimer.begin(vblCount, vblms); +#ifdef HAS_SND + emu_sndInit(); +#endif usbnavpad = 0; } diff --git a/MCUME_teensy41/teensy800/emuapi.h b/MCUME_teensy41/teensy800/emuapi.h index 1e2327c..5dd6130 100644 --- a/MCUME_teensy41/teensy800/emuapi.h +++ b/MCUME_teensy41/teensy800/emuapi.h @@ -2,124 +2,14 @@ #define EMUAPI_H #include "platform_config.h" - -#define CUSTOM_SND 1 -//#define TIMER_REND 1 -#define EXTRA_HEAP 0x10 - -// Title: < > -#define TITLE " Atari 800 Emulator" -#define ROMSDIR "800" - -#define emu_Init(ROM) {at8_Init(); at8_Start(ROM);} -#define emu_Step(x) {at8_Step();} -#define emu_Input(x) {at8_Input(x);} - -#define MAX_FILENAME_PATH 64 -#define NB_FILE_HANDLER 4 -#define PALETTE_SIZE 256 -#define VID_FRAME_SKIP 0x0 -#define TFT_VBUFFER_YCROP 0 -#define SINGLELINE_RENDERING 1 - -#define R32(rgb) ((rgb>>16)&0xff) -#define G32(rgb) ((rgb>>8)&0xff) -#define B32(rgb) (rgb & 0xff) +#include "emucfg.h" #define ACTION_NONE 0 -#define ACTION_MAXKBDVAL 16 -#define ACTION_EXITKBD 128 -#define ACTION_RUN1 129 -#define ACTION_RUN2 130 -#define ACTION_RUN3 131 - -#ifdef KEYMAP_PRESENT - -#define keylables_map0_0 (char *)"qwertyuiop\x1a" -#define keylables_map0_1 (char *)" asdfghjkl\x19" -#define keylables_map0_2 (char *)" zxcvbnm,.;/" -#define keylables_map0_3 (char *)" +\x10-" -const unsigned short key_map0[] = { - 'q','w','e','r','t','y','u','i','o','p',127, //lowecase - 0,'a','s','d','f','g','h','j','k','l',10, - 0,'z','x','c','v','b','n','m',',','.',';','/', - 0,0,0,0, - 0,'+',' ','-' - }; - -#define keylables_map1_0 (char *)" \x1a" -#define keylables_map1_1 (char *)" \x19" -#define keylables_map1_2 (char *)" <>:?" -#define keylables_map1_3 (char *)" =\x10 " -const unsigned short key_map1[] = { - '1','2','3','4','5','6','7','8','9','0',127, // digit keys - 0, 0,0,0,0,0,0,0,0,0,10, - 0, 0,0,0,0,0,0,0,'<','>',':','?', - 154,152,151,153, //U L R D - 0,'=',' ',0 - }; - -#define keylables_map2_0 (char *)"!\"#$%^&*()@" -#define keylables_map2_1 (char *)" \x19" -#define keylables_map2_2 (char *)" <>:?" -#define keylables_map2_3 (char *)" =\x10 " -const unsigned short key_map2[] = { - '!','"','#','$','%','^','&','*','(',')','@', // shiftothers - 9, 0,0,0,0,0,0,0,0,0,10, - 0, 0,0,0,0,0,0,0,'<','>',':','?', - 154,152,151,153, //U L R D - 0,'=',' ',0 - }; - -#define keylables_map3_0 (char *)"1234567890 " -#define keylables_map3_1 (char *)" " -#define keylables_map3_2 (char *)" " -#define keylables_map3_3 (char *)" " - -const unsigned short key_map3[] = { - '1','2','3','4','5','6','7','8','9','0',0, // digit keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 154,152,151,153, //U L R D - 0,0,' ',0 - }; - -#define keylables_map4_0 (char *)" " -#define keylables_map4_1 (char *)" " -#define keylables_map4_2 (char *)" " -#define keylables_map4_3 (char *)" " - -const unsigned short key_map4[] = { - 0,0,0,0,0,0,0,0,0,0,0, // function keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 154,152,151,153, //U L R D - 0,0,' ',0 - }; - -#define keylables_map5_0 (char *)" " -#define keylables_map5_1 (char *)" " -#define keylables_map5_2 (char *)" " -#define keylables_map5_3 (char *)" " - -const unsigned short key_map5[] = { - 0,0,0,0,0,0,0,0,0,0,0, // extra keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 154,152,151,153, //U L R D - 0,0,' ',0 - }; - -const unsigned short matkeys[] = { - 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 - 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 - 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 - 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN - 0x510,0x010,0x110,0x310, // row 4 - }; - -#endif +#define ACTION_RUN1 1 +#define ACTION_RUN2 2 +#define FORCE_VGATIMERVSYNC 1 +#define SUPPORT_HIRES 1 #define MASK_JOY2_RIGHT 0x0001 #define MASK_JOY2_LEFT 0x0002 @@ -136,24 +26,25 @@ const unsigned short matkeys[] = { #define MASK_JOY1_BTN 0x1000 #define MASK_KEY_USER4 0x2000 +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) #ifdef __cplusplus extern "C" { -#else -#define bool unsigned char +extern void emu_init(int hires=0); +extern void emu_start(int vblms, void * callback, int forcetimervsync=0); #endif - -extern void emu_init(void); -extern void emu_start(void); extern void emu_printf(const char * text); extern void emu_printi(int val); extern void emu_printh(int val); extern void * emu_Malloc(unsigned int size); extern void * emu_MallocI(unsigned int size); extern void emu_Free(void * pt); +extern void * emu_SMalloc(unsigned int size); +extern void emu_SFree(void * pt); extern int emu_FileOpen(const char * filepath, const char * mode); extern int emu_FileRead(void * buf, int size, int handler); +extern int emu_FileWrite(void * buf, int size, int handler); extern int emu_FileGetc(int handler); extern int emu_FileSeek(int handler, int seek, int origin); extern int emu_FileTell(int handler); @@ -164,24 +55,23 @@ extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size); extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek); extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index); -extern void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride); -extern void emu_DrawLine(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line); extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line); +extern void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride); extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line); -extern void emu_CopyLine(int width, int height, int ysrc, int ydst); extern void emu_DrawVsync(void); extern int emu_FrameSkip(void); -extern void * emu_LineBuffer(int line); -extern void emu_tweakVideo(int shiftdelta, int numdelta, int denomdelta); +extern int emu_IsVga(void); +extern int emu_IsVgaHires(void); -extern bool menuActive(void); +extern int menuActive(void); extern char * menuSelection(void); extern char * menuSecondSelection(void); -extern void toggleMenu(bool on); +extern void toggleMenu(int on); extern int handleMenu(unsigned short bClick); extern int handleOSKB(void); -extern void toggleOSKB(bool forceon); +extern void toggleOSKB(int forceon); extern void emu_InitJoysticks(void); extern int emu_SwapJoysticks(int statusOnly); @@ -190,6 +80,7 @@ extern int emu_ReadKeys(void); extern int emu_GetPad(void); extern int emu_GetMouse(int *x, int *y, int *buts); extern int emu_MouseDetected(void); +extern int emu_GetJoystick(void); extern int emu_KeyboardDetected(void); extern int emu_ReadAnalogJoyX(int min, int max); extern int emu_ReadAnalogJoyY(int min, int max); diff --git a/MCUME_teensy41/teensy800/emucfg.h b/MCUME_teensy41/teensy800/emucfg.h new file mode 100644 index 0000000..fbf7e77 --- /dev/null +++ b/MCUME_teensy41/teensy800/emucfg.h @@ -0,0 +1,115 @@ +#ifndef EMUCFG_H +#define EMUCFG_H + +#include "wrapemu.h" + +// Title: < > +#define TITLE " Atari 800 Emulator" +#define ROMSDIR "800" + +#define emu_Init(ROM) {at8_Init(); at8_Start(ROM);} +#define emu_Step(x) {at8_Step();} +#define emu_Input(x) {at8_Input(x);} + +#define MAX_FILENAME_PATH 64 +#define NB_FILE_HANDLER 4 + +#define PALETTE_SIZE 256 +#define VID_FRAME_SKIP 0x0 +#define TFT_VBUFFER_YCROP 0 +#define SINGLELINE_RENDERING 1 +#define CUSTOM_SND 1 +//#define TIMER_REND 1 +//#define EXTPAD 1 +#define EXTRA_HEAP 0x10 +#define FILEBROWSER 1 + + +#ifdef KEYMAP_PRESENT + +#define keylables_map0_0 (char *)"qwertyuiop\x1a" +#define keylables_map0_1 (char *)" asdfghjkl\x19" +#define keylables_map0_2 (char *)" zxcvbnm,.;/" +#define keylables_map0_3 (char *)" +\x10-" +const unsigned short key_map0[] = { + 'q','w','e','r','t','y','u','i','o','p',127, //lowecase + 0,'a','s','d','f','g','h','j','k','l',10, + 0,'z','x','c','v','b','n','m',',','.',';','/', + 0,0,0,0, + 0,'+',' ','-' + }; + +#define keylables_map1_0 (char *)" \x1a" +#define keylables_map1_1 (char *)" \x19" +#define keylables_map1_2 (char *)" <>:?" +#define keylables_map1_3 (char *)" =\x10 " +const unsigned short key_map1[] = { + '1','2','3','4','5','6','7','8','9','0',127, // digit keys + 0, 0,0,0,0,0,0,0,0,0,10, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 154,152,151,153, //U L R D + 0,'=',' ',0 + }; + +#define keylables_map2_0 (char *)"!\"#$%^&*()@" +#define keylables_map2_1 (char *)" \x19" +#define keylables_map2_2 (char *)" <>:?" +#define keylables_map2_3 (char *)" =\x10 " +const unsigned short key_map2[] = { + '!','"','#','$','%','^','&','*','(',')','@', // shiftothers + 9, 0,0,0,0,0,0,0,0,0,10, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 154,152,151,153, //U L R D + 0,'=',' ',0 + }; + +#define keylables_map3_0 (char *)"1234567890 " +#define keylables_map3_1 (char *)" " +#define keylables_map3_2 (char *)" " +#define keylables_map3_3 (char *)" " + +const unsigned short key_map3[] = { + '1','2','3','4','5','6','7','8','9','0',0, // digit keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 154,152,151,153, //U L R D + 0,0,' ',0 + }; + +#define keylables_map4_0 (char *)" " +#define keylables_map4_1 (char *)" " +#define keylables_map4_2 (char *)" " +#define keylables_map4_3 (char *)" " + +const unsigned short key_map4[] = { + 0,0,0,0,0,0,0,0,0,0,0, // function keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 154,152,151,153, //U L R D + 0,0,' ',0 + }; + +#define keylables_map5_0 (char *)" " +#define keylables_map5_1 (char *)" " +#define keylables_map5_2 (char *)" " +#define keylables_map5_3 (char *)" " + +const unsigned short key_map5[] = { + 0,0,0,0,0,0,0,0,0,0,0, // extra keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 154,152,151,153, //U L R D + 0,0,' ',0 + }; + +const unsigned short matkeys[] = { + 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 + 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 + 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 + 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN + 0x510,0x010,0x110,0x310, // row 4 + }; + +#endif + +#endif diff --git a/MCUME_teensy41/teensy800/platform_config.h b/MCUME_teensy41/teensy800/platform_config.h index a27370c..914d152 100644 --- a/MCUME_teensy41/teensy800/platform_config.h +++ b/MCUME_teensy41/teensy800/platform_config.h @@ -4,13 +4,13 @@ #define TEECOMPUTER 1 #ifdef TEECOMPUTER -//#define ILI9341 1 -//#define ST7789 1 -//#define TFTSPI1 1 -#define HAS_T4_VGA 1 +#define TFTSPI1 1 +//#define HAS_T4_VGA 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 -#define INVX 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 #define PT8211 1 #else @@ -19,7 +19,11 @@ //#define INVX 1 #define INVY 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 +#define PT8211 1 #endif diff --git a/MCUME_teensy41/teensy800/t4_dsp.cpp b/MCUME_teensy41/teensy800/t4_dsp.cpp new file mode 100644 index 0000000..43301fa --- /dev/null +++ b/MCUME_teensy41/teensy800/t4_dsp.cpp @@ -0,0 +1,1774 @@ +/* + TFT/VGA driver + DMA TFT driver based on C64 ILI9341 dma driver from Frank Bösing, 2017 +*/ + +#include "T4_DSP.h" + +#include +#include + +#include "font8x8.h" + +// TFT constants and variables +#define TFT_LINEARINT 1 +#define LINEARINT_HACK 1 +#define DMA_LINES_PER_BLOCK 64 +#define DMA_NUM_SETTINGS 4 + +#define TFT_SWRESET 0x01 +#define TFT_SLPOUT 0x11 +#define TFT_INVON 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_MADCTL 0x36 +#define TFT_PIXFMT 0x3A +#define TFT_MADCTL_MY 0x80 +#define TFT_MADCTL_MX 0x40 +#define TFT_MADCTL_MV 0x20 +#define TFT_MADCTL_ML 0x10 +#define TFT_MADCTL_RGB 0x00 +#define TFT_MADCTL_BGR 0x08 +#define TFT_MADCTL_MH 0x04 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) +//#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) +//#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) +//#define R16(rgb) ((rgb>>8)&0xf8) +//#define G16(rgb) ((rgb>>3)&0xfc) +//#define B16(rgb) ((rgb<<3)&0xf8) + +// LPSPI4 = SPI0 in Teensy 4.0 +// LPSPI3 = SPI1 in Teensy 4.0 +// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) + +#ifdef TFTSPI1 +#define SPI SPI1 +#define LPSPIP_TDR LPSPI3_TDR +#define LPSPIP_CR LPSPI3_CR +#define LPSPIP_CFGR1 LPSPI3_CFGR1 +#define LPSPIP_TCR LPSPI3_TCR +#define LPSPIP_DER LPSPI3_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX +#else +#define LPSPIP_TDR LPSPI4_TDR +#define LPSPIP_CR LPSPI4_CR +#define LPSPIP_CFGR1 LPSPI4_CFGR1 +#define LPSPIP_TCR LPSPI4_TCR +#define LPSPIP_DER LPSPI4_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX +#endif + +#define SPICLOCK 60000000 +#define SPI_MODE SPI_MODE0 + +// VGA constants and macros +typedef uint8_t vga_pixel; +#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) + +static DMASetting dmasettings[DMA_NUM_SETTINGS]; +static DMAChannel dmatx; +static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K +static volatile uint8_t rstop = 0; +static volatile bool cancelled = false; +static volatile uint8_t curTransfer = 0; +static uint8_t nbTransfer = 0; +static uint16_t * tft_buffer; +static int tft_width; +static int tft_height; +static int tft_stride; + +#define DELAY_MASK 0x80 +PROGMEM static const uint8_t init_commands[] = { + 1+DELAY_MASK, TFT_SWRESET, 150, + 1+DELAY_MASK, TFT_SLPOUT, 255, + 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, + 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, + 1, TFT_INVON, + 1, TFT_DISPON, + 0 +}; + +// VGA constants and variables +// Objective: +// generates VGA signal fully in hardware with as little as possible CPU help + +// Principle: +// QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) +// 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate +// RGB out, combined to create 8bits(/12bits) output. + +// Note: +// - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels +// - experimental resolution: 352x240,352x480 +// - experimental resolution: 512x240,512x480 (not stable) +// - video memory is allocated using malloc in T4 heap +// - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing +// but tried to be compensated by pixel shifting +// - Default is 8bits RRRGGGBB (332) +// But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! +// - Only ok at 600MHz else some disturbances visible + + + +#define TOP_BORDER 40 +#define PIN_HBLANK 15 + +#define PIN_R_B2 33 +#define PIN_R_B1 4 +#define PIN_R_B0 3 +#define PIN_G_B2 2 +#define PIN_G_B1 13 +#define PIN_G_B0 11 +#define PIN_B_B1 12 +#define PIN_B_B0 10 + + +#define DMA_HACK 0x80 + +#define R16(rgb) ((rgb>>8)&0xf8) +#define G16(rgb) ((rgb>>3)&0xfc) +#define B16(rgb) ((rgb<<3)&0xf8) + +// VGA 640x480@60Hz +// Screen refresh rate 60 Hz +// Vertical refresh 31.46875 kHz +// Pixel freq. 25.175 MHz +// +// Visible area 640 25.422045680238 us +// Front porch 16 0.63555114200596 us +// Sync pulse 96 3.8133068520357 us +// Back porch 48 1.9066534260179 us +// Whole line 800 31.777557100298 us + +#define frame_freq 60.0 // Hz +#define line_freq 31.46875 // KHz +#define pix_freq (line_freq*800) // KHz (25.175 MHz) + +// pix_period = 39.7ns +// H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) +#define frontporch_pix 20 //16 +#define backporch_pix 44 //48 + +// Flexio Clock +// PLL3 SW CLOCK (3) => 480 MHz +// PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) +#define FLEXIO_CLK_SEL_PLL3 3 +#define FLEXIO_CLK_SEL_PLL5 2 + +/* Set video PLL */ +// There are /1, /2, /4, /8, /16 post dividers for the Video PLL. +// The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, +// and CCM_ANALOG_MISC2 register sets according to the following equation. +// PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + +// nfact: +// This field controls the PLL loop divider. +// Valid range for DIV_SELECT divider value: 27~54. + +#define POST_DIV_SELECT 2 + +// Full buffer including back/front porch +static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; +static uint32_t dstbuffer __attribute__((aligned(32))); + +// Visible vuffer +static vga_pixel * vga_buffer; +static int vga_width; +static int vga_height; +static int vga_stride; + +static int maxpixperline; +static int left_border; +static int right_border; +static int line_double; +static int pix_shift; +static int ref_div_select; +static int ref_freq_num; +static int ref_freq_denom; +static int ref_pix_shift; +static int combine_shiftreg; + +#ifdef DEBUG +static uint32_t ISRTicks_prev = 0; +volatile uint32_t ISRTicks = 0; +#endif + +uint8_t T4_DSP::_rst; +uint8_t T4_DSP::_cs; +uint8_t T4_DSP::_dc; +uint8_t T4_DSP::_mosi; +uint8_t T4_DSP::_sclk; +uint8_t T4_DSP::_vsync_pin = -1; +DMAChannel T4_DSP::flexio1DMA; +DMAChannel T4_DSP::flexio2DMA; + +static volatile uint32_t VSYNC = 0; +static volatile uint32_t currentLine=0; +#define NOP asm volatile("nop\n\t"); +static gfx_mode_t gfxmode = MODE_UNDEFINED; + + +FASTRUN void T4_DSP::TFT_isr(void) { + dmatx.clearInterrupt(); + curTransfer++; + if (curTransfer >= nbTransfer) { + curTransfer = 0; + if (cancelled) { + dmatx.disable(); + rstop = 1; + } + } + arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); +} + +FASTRUN void T4_DSP::QT3_isr(void) { + TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); + TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); + + cli(); + + // V-PULSE + if (currentLine > 0) { + digitalWrite(_vsync_pin, 1); + VSYNC = 0; + } else { + digitalWrite(_vsync_pin, 0); + VSYNC = 1; + } + + currentLine++; + currentLine = currentLine % 525; + + + uint32_t y = (currentLine - TOP_BORDER) >> line_double; + // Visible area + + if (y >= 0 && y < vga_height) { + // Disable DMAs + //DMA_CERQ = flexio2DMA.channel; + //DMA_CERQ = flexio1DMA.channel; + + // Setup source adress + // Aligned 32 bits copy + unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; + flexio2DMA.TCD->SADDR = p; + if (pix_shift & DMA_HACK) + { + // Unaligned copy + uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; + flexio1DMA.TCD->SADDR = p2; + } + else { + p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 + flexio1DMA.TCD->SADDR = p; + } + + // Enable DMAs + //flexio2DMA.enable(); + //flexio1DMA.enable(); + DMA_SERQ = flexio2DMA.channel; + DMA_SERQ = flexio1DMA.channel; + arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); + } + sei(); + +#ifdef DEBUG + ISRTicks++; +#endif + asm volatile("dsb"); +} + +static void setDmaStruct() { + uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; + uint16_t * fb = (uint16_t*)malloc(remaining); + tft_buffer = fb; + tft_width = TFT_WIDTH; + tft_height = TFT_HEIGHT; + tft_stride = TFT_WIDTH; + uint16_t col=RGBVAL16(0x00,0x00,0x00); + int i=0; + while (remaining > 0) { + int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); + blocks[i] = fb; + for (int j=0;jATTR_DST = 1; + dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); + dmasettings[i].interruptAtCompletion(); + fb += len/2; + remaining -= len; + i++; + } + dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); + nbTransfer = i; +} + +static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 +{ +//if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; + CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE + | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 + | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); + CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; + CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock + const int div_post_pll = 1; // other values: 2,4 + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass +} + +T4_DSP::T4_DSP() +{ + _cs = TFT_CS; + _dc = TFT_DC; + _rst = TFT_RST; + _mosi = TFT_MOSI; + _sclk = TFT_SCLK; + pinMode(_dc, OUTPUT); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, 1); + digitalWrite(_dc, 1); + _vsync_pin = 8; +} + + +void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { + int dx=0; + int dy=0; + digitalWrite(_dc, 0); + SPI.transfer(TFT_CASET); + digitalWrite(_dc, 1); + SPI.transfer16(x1+dx); + digitalWrite(_dc, 1); + SPI.transfer16(x2+dx); + digitalWrite(_dc, 0); + SPI.transfer(TFT_PASET); + digitalWrite(_dc, 1); + SPI.transfer16(y1+dy); + digitalWrite(_dc, 1); + SPI.transfer16(y2+dy); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + return; +} + +void T4_DSP::tft_setup(bool isST) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + // RESET if reset pin defined + if (_rst != 0xff) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + const uint8_t *addr = init_commands; + uint8_t count; + digitalWrite(_cs, 0); + while (count = *addr++) { + uint8_t command = *addr++; + if ( (command == TFT_INVON) && (!isST) ) { + // Skip TFT_INVON for ILI + } + else { + digitalWrite(_dc, 0); // command + SPI.transfer(command); + uint16_t ms = count & DELAY_MASK; + count &= ~DELAY_MASK; + while (--count > 0) { // data + uint8_t data = *addr++; + if ( (command == TFT_MADCTL) && (isST) ) { + data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; + } + digitalWrite(_dc, 1); + SPI.transfer(data); + } + if (ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + digitalWrite(_cs, 1); + SPI.endTransaction(); + delay(2); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + } + } + } + digitalWrite(_cs, 1); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + SPI.endTransaction(); + /* + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_dc, 0); + digitalWrite(_cs, 0); + SPI.transfer(TFT_MADCTL); + digitalWrite(_dc, 1); + SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); + // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); + digitalWrite(_cs, 1); + SPI.endTransaction(); + */ + cancelled = false; +} + +// display VGA image +gfx_error_t T4_DSP::begin(gfx_mode_t mode) +{ + uint32_t flexio_clock_div; + combine_shiftreg = 0; +// int div_select = 49; +// int num = 135; +// int denom = 100; + int div_select = 20; + int num = 9800; + int denom = 10000; + int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; + int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; + set_videoClock(div_select,num,denom,true); + +#ifdef DEBUG + Serial.println(mode); + Serial.println("mode"); +#endif + + switch(mode) + { + case MODE_TFTILI_320x240: +#ifdef DEBUG + Serial.println("TFTILI_320x240"); +#endif + tft_setup(false); + gfxmode = mode; + break; + case MODE_TFTST_320x240: +#ifdef DEBUG + Serial.println("TFTST_320x240"); +#endif + tft_setup(true); + gfxmode = mode; + break; + + case MODE_VGA_320x240: +#ifdef DEBUG + Serial.println("VGA_320x240"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_320x480: +#ifdef DEBUG + Serial.println("VGA_320x480"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_640x240: +#ifdef DEBUG + Serial.println("VGA_640x240"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/pix_freq; + line_double = 1; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_640x480: +#ifdef DEBUG + Serial.println("VGA_640x480"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = (flexio_freq/pix_freq); + line_double = 0; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_512x240: +#ifdef DEBUG + Serial.println("VGA_512x240"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 1; + pix_shift = 0; + break; + + case MODE_VGA_512x480: +#ifdef DEBUG + Serial.println("VGA_512x480"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 0; + pix_shift = 0; + break; + + case MODE_VGA_352x240: +#ifdef DEBUG + Serial.println("VGA_352x240"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_352x480: +#ifdef DEBUG + Serial.println("VGA_352x480"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + } + + if (mode >= MODE_VGA_320x240) + { + if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { + fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); + digitalWrite(_cs, 0); + digitalWrite(_dc, 0); + SPI.transfer(TFT_DISPOFF); + digitalWrite(_cs, 1); + delay(20); + digitalWrite(_cs, 0); + digitalWrite(_cs, 1); + } + gfxmode = mode; + + maxpixperline = vga_stride; + // Save param for tweek adjustment + ref_div_select = div_select; + ref_freq_num = num; + ref_freq_denom = denom; + ref_pix_shift = pix_shift; + +#ifdef DEBUG + Serial.println("frequency"); + Serial.println(flexio_freq); + Serial.println("div"); + Serial.println(flexio_freq/pix_freq); +#endif + + pinMode(_vsync_pin, OUTPUT); + pinMode(PIN_HBLANK, OUTPUT); + + /* Basic pin setup FlexIO1 */ + pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 + pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 + pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 + pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 + /* Basic pin setup FlexIO2 */ + pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 + pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 + pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 + pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 + + /* High speed and drive strength configuration */ + *(portControlRegister(PIN_G_B2)) = 0xFF; + *(portControlRegister(PIN_R_B0)) = 0xFF; + *(portControlRegister(PIN_R_B1)) = 0xFF; + *(portControlRegister(PIN_R_B2)) = 0xFF; + *(portControlRegister(PIN_B_B0)) = 0xFF; + *(portControlRegister(PIN_B_B1)) = 0xFF; + *(portControlRegister(PIN_G_B0)) = 0xFF; + *(portControlRegister(PIN_G_B1)) = 0xFF; + + /* Set clock for FlexIO1 and FlexIO2 */ + CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) + | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); + CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) + | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); + + + /* Set up pin mux FlexIO1 */ + *(portConfigRegister(PIN_G_B2)) = 0x14; + *(portConfigRegister(PIN_R_B0)) = 0x14; + *(portConfigRegister(PIN_R_B1)) = 0x14; + *(portConfigRegister(PIN_R_B2)) = 0x14; + /* Set up pin mux FlexIO2 */ + *(portConfigRegister(PIN_B_B0)) = 0x14; + *(portConfigRegister(PIN_B_B1)) = 0x14; + *(portConfigRegister(PIN_G_B0)) = 0x14; + *(portConfigRegister(PIN_G_B1)) = 0x14; + + /* Enable the clock */ + CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + /* Enable the FlexIO with fast access */ + FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + + uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; + uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; + + /* Shifter 0 registers for FlexIO2 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 + inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter + stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled + startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable + timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 + timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock + pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output + pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity + shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode + /* Shifter 0 registers for FlexIO1 */ + FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + /* Shifter 0 registers for FlexIO1 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 + FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + if (combine_shiftreg) { + pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled + FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + } + /* Timer 0 registers for FlexIO2 */ + timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset + timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output + timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset + timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare + timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert + stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled + startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled + if (combine_shiftreg) { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag + } + else { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag + } + triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low + triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected + pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled + //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 + //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high + timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode + // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) + + int shifts_per_transfer; + if (combine_shiftreg) { + shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 + } + else { + shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 + } + FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); + /* Timer 0 registers for FlexIO1 */ + FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); +#ifdef DEBUG + Serial.println("FlexIO setup complete"); +#endif + + /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ + if (combine_shiftreg) { + FLEXIO2_SHIFTSDEN |= (1<<1); + FLEXIO1_SHIFTSDEN |= (1<<1); + } + else { + FLEXIO2_SHIFTSDEN |= (1<<0); + FLEXIO1_SHIFTSDEN |= (1<<0); + } + /* Disable DMA channel so it doesn't start transferring yet */ + flexio1DMA.disable(); + flexio2DMA.disable(); + /* Set up DMA channel to use Shifter 0 trigger */ + flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); + flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); + + + if (combine_shiftreg) { + flexio2DMA.TCD->NBYTES = 8; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 8; + flexio2DMA.TCD->CITER = maxpixperline / 8; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + flexio1DMA.TCD->NBYTES = 8; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 8; + flexio1DMA.TCD->CITER = maxpixperline / 8; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Setup DMA2 Flexio2 copy + flexio2DMA.TCD->NBYTES = 4; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 4; + flexio2DMA.TCD->CITER = maxpixperline / 4; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + // Setup DMA1 Flexio1 copy + // Use pixel shift to avoid color smearing? + if (pix_shift & DMA_HACK) + { + if (pix_shift & 0x3 == 0) { + // Aligned 32 bits copy (32bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Unaligned (source) 32 bits copy (8bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 1; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion + } + } + else + { + // Aligned 32 bits copy + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + } + +#ifdef DEBUG + Serial.println("DMA setup complete"); +#endif + + // enable clocks for QTIMER3: generates the 15KHz for hsync + // Pulse: + // low : 3.8133 us => 569x6.7ns + // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) + // (OLD TEST) + // (4us low, 28us high => 32us) + // (597x6.7ns for 4us) + // (4179x6.7ns for 28us) + CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 + //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 + + #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz + #define MARGIN_D 1000 + + TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer + // Invert output pin as we want the interupt on rising edge + TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) + TMR3_CNTR3 = 0; + TMR3_LOAD3 = 0; + + /* Inverted timings */ + unsigned long long cpu_freq = F_CPU; + unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; + int rate2 = rate; + + int substract = 1; + if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { + substract=5; + rate2=1652; + } + + #ifdef DEBUG + Serial.print("MARGIN_N is: "); + Serial.println(rate2, DEC); + Serial.print("SUBSTRACT is: "); + Serial.println(substract, DEC); +#endif + TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; + TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; + /* + TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; + */ + TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on + TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), + // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) + //configure Teensy pin Compare output + IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 + attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function + NVIC_ENABLE_IRQ(IRQ_QTIMER3); +#ifdef DEBUG + Serial.println("QTIMER3 setup complete"); + Serial.print("V-PIN is "); + Serial.println(_vsync_pin); +#endif + + /* initialize gfx buffer */ + if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift + if (gfxbuffer == NULL) return(GFX_ERROR); +#ifdef DEBUG + Serial.println("Memory allocated"); +#endif + + memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); + vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; +#ifdef DEBUG + Serial.println(vga_stride); + Serial.println(vga_height); + Serial.println("Screen cleared"); +#endif + } + + return(GFX_OK); +} + +gfx_mode_t T4_DSP::getMode(void) +{ + return gfxmode; +} + +void T4_DSP::startRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + curTransfer = 0; + rstop = 0; + //dmatx.begin(true); + dmatx.attachInterrupt(TFT_isr); + setDmaStruct(); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + + digitalWrite(_cs, HIGH); + SPI.begin(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + + LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: + LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX + LPSPIP_TCR = 15; // Framesize 16 Bits + //LPSPIP_FCR = 0; // Fifo Watermark + LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable + LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: + dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); + + dmatx = dmasettings[0]; + digitalWrite(_cs, 0); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + dmatx.enable(); + } +} + + +void T4_DSP::stopRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + rstop = 1; + unsigned long m = millis(); + cancelled = true; + while (!rstop) { + if ((millis() - m) > 100) break; + delay(10); + asm volatile("wfi"); + }; + rstop = 0; + delay(50); + cancelled = false; + dmatx.detachInterrupt(); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + SPI.end(); +#ifdef ST7789 +// begin(gfxmode); +#endif + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + } +} + +int T4_DSP::get_frame_buffer_size(int *width, int *height) { + if (gfxmode < MODE_VGA_320x240) { + if (width != nullptr) *width = tft_width; + if (height != nullptr) *height = tft_height; + return tft_stride; + } + else { + if (width != nullptr) *width = vga_width; + if (height != nullptr) *height = vga_height; + return vga_stride; + } +} + +void T4_DSP::waitSync() +{ + if (gfxmode >= MODE_VGA_320x240) { + while (VSYNC == 0) {}; + } +} + +void T4_DSP::waitLine(int line) +{ + if (gfxmode >= MODE_VGA_320x240) { + while (currentLine != line) {}; + } +} + +/*********************************************************************************************** + No DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreenNoDma(uint16_t color) { + if (gfxmode < MODE_VGA_320x240) { + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + int i,j; + for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(arx, ary, arx+arw-1, ary+arh-1); + bitmap = bitmap + bmp_offy*w + bmp_offx; + for (int row=0;row> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + bits = *charpt++; + //digitalWrite(_dc, 1); + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + x +=8; + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + else { + drawText(x, y, text, fgcolor, bgcolor, doublesize); + } +} + + +/*********************************************************************************************** + DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreen(uint16_t color) { + int i,j; + if (gfxmode < MODE_VGA_320x240) { + for (j=0; j> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + dst=&tft_buffer[l*tft_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + x +=8; + } + } + else { + vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); + vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); + vga_pixel * dst; + while ((c = *text++)) { + const unsigned char * charpt=&font8x8[c][0]; + int l=y; + for (int i=0;i<8;i++) + { + unsigned char bits; + if (doublesize) { + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + x +=8; + } + } +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { + drawSprite(x,y,bitmap, 0,0,0,0); +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) +{ + int bmp_offx = 0; + int bmp_offy = 0; + uint16_t *bmp_ptr; + int w =*bitmap++; + int h = *bitmap++; + if ( (arw == 0) || (arh == 0) ) { + // no crop window + arx = x; + ary = y; + arw = w; + arh = h; + } + else { + if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + int l=ary; + bitmap = bitmap + bmp_offy*w + bmp_offx; + + if (gfxmode < MODE_VGA_320x240) { + for (int row=0;row tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]; + pos +=step; + } + #endif + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i 2) ) y += (tft_height-height)/2; + uint16_t * dst=&tft_buffer[y*tft_stride]; + if (width > tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]]; + pos +=step; + } +#endif + } + else if ((width*2) == tft_width) { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]]; + *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i tft_width) { + int step = ((width << 8)/tft_width); + int pos = 0; + for (int i=0; i> 8]]; + pos +=step; + } + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = pix; + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i +#include +#endif + +#include "platform_config.h" +#include "iopins.h" + + + +#ifndef TFT_WIDTH +#define TFT_WIDTH 320 +#endif +#define TFT_REALWIDTH 320 + +#ifndef TFT_HEIGHT +#define TFT_HEIGHT 240 +#endif +#define TFT_REALHEIGHT 240 + + +typedef enum gfx_mode_t +{ + MODE_UNDEFINED = 0, + MODE_TFTILI_320x240 = 1, + MODE_TFTST_320x240 = 2, + MODE_VGA_320x240 = 3, + MODE_VGA_320x480 = 4, + MODE_VGA_352x240 = 5, + MODE_VGA_352x480 = 6, + MODE_VGA_512x240 = 7, + MODE_VGA_512x480 = 8, + MODE_VGA_640x240 = 9, + MODE_VGA_640x480 = 10 +} gfx_mode_t; + +typedef enum gfx_error_t +{ + GFX_OK = 0, + GFX_ERROR = -1 +} gfx_error_t; + + +#ifdef __cplusplus + +class T4_DSP +{ + public: + T4_DSP(); + + gfx_error_t begin(gfx_mode_t mode); + gfx_mode_t getMode(void); + void startRefresh(void); + void stopRefresh(); + + int get_frame_buffer_size(int *width, int *height); + void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); + + // wait next Vsync + void waitSync(); + void waitLine(int line); + + // NoDMA functions + void fillScreenNoDma(uint16_t color); + void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + // DMA functions + void fillScreen(uint16_t color); + void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + void writeLine(int width, int height, int y, uint16_t *buf); + void writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + void writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16); + void writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + + protected: + static uint8_t _rst, _cs, _dc; + static uint8_t _mosi, _sclk; + static uint8_t _vsync_pin; + static DMAChannel flexio1DMA; + static DMAChannel flexio2DMA; + void tft_setup(bool isST); + static void TFT_isr(void); + static void QT3_isr(void); +}; + +#endif +#endif diff --git a/MCUME_teensy41/teensy800/teensy800.ino b/MCUME_teensy41/teensy800/teensy800.ino index 9e51ab6..fa1911b 100644 --- a/MCUME_teensy41/teensy800/teensy800.ino +++ b/MCUME_teensy41/teensy800/teensy800.ino @@ -3,135 +3,20 @@ extern "C" { #include "emuapi.h" } -extern "C" { -#include "atari800.h" -} - -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -TFT_T_DMA tft; -#else -#include "tft_t_dma.h" -TFT_T_DMA tft = TFT_T_DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, TFT_TOUCH_CS, TFT_TOUCH_INT); -#endif - -bool vgaMode = false; - -static unsigned char palette8[PALETTE_SIZE]; -static unsigned short palette16[PALETTE_SIZE]; -static IntervalTimer myTimer; -volatile boolean vbl=true; -static int skip=0; -static elapsedMicros tius; - -static void vblCount() { - if (vbl) { - vbl = false; - } else { - vbl = true; - } -} - -void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) -{ - if (index>8, - 320 & 0xFF, // YEND = 320 - ST7735_INVON , DELAY, // 7: hack - 10, - ST7735_NORON , DELAY, // 8: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 9: Main screen turn on, no args, w/delay - 255 -#endif -}; - -static void dmaInterrupt() { - dmatx.clearInterrupt(); - curTransfer++; - if (curTransfer >= nbTransfer) { - curTransfer = 0; - if (cancelled) { - dmatx.disable(); - rstop = 1; - } - } - arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2); -} - -static void setDmaStruct() { - uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; - int i=0; - uint16_t col=RGBVAL16(0x00,0x00,0x00);; - while (remaining > 0) { - uint16_t * fb = blocks[i]; - int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining); -#ifdef TFT_DEBUG - Serial.println((unsigned long)blocks[i]); - Serial.println(remaining); -#endif - switch (i) { - case 0: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb0[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0x00); -#endif - break; - case 1: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb1[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0xff); -#endif - break; - case 2: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb2[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0x00,0xff); -#endif - break; - case 3: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb3[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0xff,0x00,0xff); -#endif - break; - } - blocks[i] = fb; - if (blocks[i] == 0) { - Serial.print("ILI9341 allocaltion failed for block "); - Serial.println(i); - delay(10000); - } - - for (int j=0;jATTR_DST = 1; - dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); - dmasettings[i].interruptAtCompletion(); - remaining -= len; - i++; - } - dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); - nbTransfer = i; -#ifdef TFT_DEBUG - Serial.println(nbTransfer); -#endif -} - - -TFT_T_DMA::TFT_T_DMA(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso, uint8_t touch_cs, uint8_t touch_irq) -{ - _cs = cs; - _dc = dc; - _rst = rst; - _mosi = mosi; - _sclk = sclk; - _miso = miso; - pinMode(_dc, OUTPUT); - pinMode(_cs, OUTPUT); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); - if ( (touch_cs != 255) && (touch_irq != 255) ) { - _touch_irq = touch_irq; - _touch_cs = touch_cs; - pinMode(_touch_cs, OUTPUT); - pinMode(touch_irq, INPUT_PULLUP); - digitalWrite(_touch_cs, 1); - } -} - - -void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { - int dx=0; - int dy=0; -#ifdef ST7789 - if (TFT_REALWIDTH == TFT_REALHEIGHT) - { -#ifdef ROTATE_SCREEN - if (!flipped) { - dy += 80; - } -#else - if (flipped) { - dx += 80; - } -#endif - } -#endif - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - SPI.transfer16(x1+dx); - digitalWrite(_dc, 1); - SPI.transfer16(x2+dx); - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - digitalWrite(_dc, 1); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - return; - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - - SPI.transfer16(x1+dx); - SPI.transfer16(x2+dx); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - -void TFT_T_DMA::begin(void) { - SPI.setMOSI(_mosi); - SPI.setMISO(_miso); - SPI.setSCK(_sclk); - SPI.begin(); - - // Initialize display - if (_rst != 0xff) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - const uint8_t *addr = init_commands; - digitalWrite(_cs, 0); -#ifdef ILI9341 - while (1) { - uint8_t count = *addr++; - if (count-- == 0) break; - - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - - while (count-- > 0) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - } - - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(ILI9341_DISPON); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); -#endif -#ifdef ST7789 - uint8_t numCommands, numArgs; - uint16_t ms; - numCommands = *addr++; // Number of commands to follow - while(numCommands--) { // For each command... - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - numArgs = *addr++; // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs > 1) { // For each argument... - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - numArgs--; - } - - if (numArgs) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - if(ms) { - ms = *addr++; // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - digitalWrite(_cs, 1); - SPI.endTransaction(); - delay(ms); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - } - } - digitalWrite(_cs, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - SPI.endTransaction(); - - cancelled = false; - -#ifdef FLIP_SCREEN - flipscreen(true); -#else - flipscreen(false); -#endif -#ifdef ST7789 - if (TFT_REALWIDTH != TFT_REALHEIGHT) - { - flipscreen(true); - } -#endif -}; - - - -void TFT_T_DMA::flipscreen(bool flip) -{ - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(TFT_MADCTL); - digitalWrite(_dc, 1); - if (flip) { - flipped=true; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB); -#endif -#endif - } - else { - flipped=false; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB); -#endif -#endif - } - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - -boolean TFT_T_DMA::isflipped(void) -{ - return(flipped); -} - - -#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) - - -void TFT_T_DMA::startDMA(void) { - curTransfer = 0; - rstop = 0; - //dmatx.begin(true); - dmatx.attachInterrupt(dmaInterrupt); - setDmaStruct(); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - - digitalWrite(_cs, HIGH); - SPI.begin(); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); - - - LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: - LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX - LPSPIP_TCR = 15; // Framesize 16 Bits - //LPSPIP_FCR = 0; // Fifo Watermark - LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable - LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: - dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); - - dmatx = dmasettings[0]; - digitalWrite(_cs, 0); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - dmatx.enable(); -} - - -void TFT_T_DMA::stopDMA(void) { - rstop = 0; - wait(); - delay(50); - cancelled = false; - dmatx.detachInterrupt(); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - SPI.end(); -#ifdef ST7789 - begin(); -#endif -#ifdef ILI9341 - SPI.begin(); - digitalWrite(_cs, 0); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - SPI.endTransaction(); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); -} - -void TFT_T_DMA::wait(void) { - rstop = 1; - unsigned long m = millis(); - cancelled = true; - while (!rstop) { - if ((millis() - m) > 100) break; - delay(10); - asm volatile("wfi"); - }; - rstop = 0; -} - -int TFT_T_DMA::get_frame_buffer_size(int *width, int *height){ - if (width != nullptr) *width = TFT_REALWIDTH; - if (height != nullptr) *height = TFT_REALHEIGHT; - return TFT_REALWIDTH; -} - - -/*********************************************************************************************** - Touch functions - ***********************************************************************************************/ -/* Code based on ... - * - * @file XPT2046.cpp - * @date 19.02.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the XPT2046 driver for Arduino. - */ - -#define ADC_MAX 0x0fff - -void TFT_T_DMA::enableTouchIrq() -{ - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 }; - SPI.transfer((void*)&buf[0],3); - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); -} - -//Default callibration for non flipped -#define TX_MIN 30 -#define TY_MIN 20 -#define TX_MAX 300 -#define TY_MAX 220 - -//Default callibration for flipped -#define TFX_MIN 20 -#define TFY_MIN 25 -#define TFX_MAX 288 -#define TFY_MAX 221 - -static uint16_t txMin; -static uint16_t tyMin; -static uint16_t txMax; -static uint16_t tyMax; - - -void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { - if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) { - txMin = xMin; - tyMin = yMin; - txMax = xMax; - tyMax = yMax; - } - else { - if (flipped) { - txMin = TFX_MIN; - tyMin = TFY_MIN; - txMax = TFX_MAX; - tyMax = TFY_MAX; - } - else { - txMin = TX_MIN; - tyMin = TY_MIN; - txMax = TX_MAX; - tyMax = TY_MAX; - } - } -} - - -void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - if ( TOUCH_ENABLED() ) { - uint16_t x = 0; - uint16_t y = 0; - uint16_t z1 = 0; - uint16_t z2 = 0; - uint8_t i = 0; - int16_t xraw=0, yraw=0; - - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - - for(; i < 15; i++) { - // SPI requirer 32bit aliment - uint8_t buf[12] = { - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00 - }; - SPI.transfer(&buf[0], &buf[0], 12); - y += (buf[1] << 8 | buf[2])>>3; - x += (buf[4] << 8 | buf[5])>>3; - z1 += (buf[7] << 8 | buf[8])>>3; - z2 += (buf[10] << 8 | buf[11])>>3; - } - enableTouchIrq(); - - if(i == 0) { - *oX = 0; - *oY = 0; - *oZ = 0; - } - else { - x /= i; - y /= i; - z1 /= i; - z2 /= i; - } - - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); - int z = z1 + ADC_MAX - z2; - if (flipped) { - xraw = x; - yraw = y; - } else { - xraw = ADC_MAX - x; - yraw = ADC_MAX - y; - } - xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1); - yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1); - - *oX = xraw; - *oY = yraw; - *oZ = z; - } - else - { - *oX = 0; - *oY = 0; - *oZ = 0; - } -} - -void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - readRaw(oX,oY,oZ); - // callibrate ... - if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin); - if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin); - //Serial.print(*oX); - //Serial.print(" "); - //Serial.println(*oY); -} - - -/*********************************************************************************************** - No DMA functions - ***********************************************************************************************/ -void TFT_T_DMA::fillScreenNoDma(uint16_t color) { - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - int i,j; - for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(arx, ary, arx+arw-1, ary+arh-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - bits = *charpt++; - //digitalWrite(_dc, 1); - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - x +=8; -#ifdef ILI9341 - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); -#endif - digitalWrite(_cs, 1); - SPI.endTransaction(); - } - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - - - -/*********************************************************************************************** - DMA functions - ***********************************************************************************************/ -uint16_t * TFT_T_DMA::getLineBuffer(int j) -{ - uint16_t * block=blocks[j>>6]; - return(&block[(j&0x3F)*TFT_REALWIDTH]); -} - -void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) { - uint8_t *buffer=buf; - uint8_t *src; - - int i,j,y=0; - if (width*2 <= TFT_REALWIDTH) { - for (j=0; j>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH]; - for (i=0; i>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x]; - for (i=0; i>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - block=blocks[l>>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt++; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - x +=8; - } -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { - drawSprite(x,y,bitmap, 0,0,0,0); -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) -{ - int bmp_offx = 0; - int bmp_offy = 0; - uint16_t *bmp_ptr; - - int w =*bitmap++; - int h = *bitmap++; - - - if ( (arw == 0) || (arh == 0) ) { - // no crop window - arx = x; - ary = y; - arw = w; - arh = h; - } - else { - if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - int l=ary; - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx]; - bmp_ptr = (uint16_t*)bitmap; - for (int col=0;col -#include -#include -#endif - -#include "tft_t_dma_config.h" - -#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) -#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define R16(rgb) ((rgb>>8)&0xf8) -#define G16(rgb) ((rgb>>3)&0xfc) -#define B16(rgb) ((rgb<<3)&0xf8) - -#define PAL_COLOR_MASK 0xff - -#ifdef LOHRES -#define TFT_WIDTH 240 -#define TFT_REALWIDTH 240 -#else -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 -#endif -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - -//#define WIDTH 272 -//#define HEIGHT 228 - -#define LINES_PER_BLOCK 64 -#define NR_OF_BLOCK 4 -#define SCREEN_DMA_NUM_SETTINGS NR_OF_BLOCK - - -#ifdef ILI9341 - -#define ILI9341_NOP 0x00 -#define ILI9341_SWRESET 0x01 -#define ILI9341_RDDID 0x04 -#define ILI9341_RDDST 0x09 - -#define ILI9341_SLPIN 0x10 -#define ILI9341_SLPOUT 0x11 -#define ILI9341_PTLON 0x12 -#define ILI9341_NORON 0x13 - -#define ILI9341_RDMODE 0x0A -#define ILI9341_RDMADCTL 0x0B -#define ILI9341_RDPIXFMT 0x0C -#define ILI9341_RDIMGFMT 0x0D -#define ILI9341_RDSELFDIAG 0x0F - -#define ILI9341_INVOFF 0x20 -#define ILI9341_INVON 0x21 -#define ILI9341_GAMMASET 0x26 -#define ILI9341_DISPOFF 0x28 -#define ILI9341_DISPON 0x29 - -#define ILI9341_CASET 0x2A -#define ILI9341_PASET 0x2B -#define ILI9341_RAMWR 0x2C -#define ILI9341_RAMRD 0x2E - -#define ILI9341_PTLAR 0x30 -#define ILI9341_MADCTL 0x36 -#define ILI9341_VSCRSADD 0x37 -#define ILI9341_PIXFMT 0x3A - -#define ILI9341_FRMCTR1 0xB1 -#define ILI9341_FRMCTR2 0xB2 -#define ILI9341_FRMCTR3 0xB3 -#define ILI9341_INVCTR 0xB4 -#define ILI9341_DFUNCTR 0xB6 - -#define ILI9341_PWCTR1 0xC0 -#define ILI9341_PWCTR2 0xC1 -#define ILI9341_PWCTR3 0xC2 -#define ILI9341_PWCTR4 0xC3 -#define ILI9341_PWCTR5 0xC4 -#define ILI9341_VMCTR1 0xC5 -#define ILI9341_VMCTR2 0xC7 - -#define ILI9341_RDID1 0xDA -#define ILI9341_RDID2 0xDB -#define ILI9341_RDID3 0xDC -#define ILI9341_RDID4 0xDD - -#define ILI9341_GMCTRP1 0xE0 -#define ILI9341_GMCTRN1 0xE1 - -#define ILI9341_MADCTL_MY 0x80 -#define ILI9341_MADCTL_MX 0x40 -#define ILI9341_MADCTL_MV 0x20 -#define ILI9341_MADCTL_ML 0x10 -#define ILI9341_MADCTL_RGB 0x00 -#define ILI9341_MADCTL_BGR 0x08 -#define ILI9341_MADCTL_MH 0x04 - -#define TFT_CASET ILI9341_CASET -#define TFT_PASET ILI9341_PASET -#define TFT_RAMWR ILI9341_RAMWR -#define TFT_MADCTL ILI9341_MADCTL - -#endif - - -#ifdef ST7789 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_RGB 0x00 -#define ST77XX_MADCTL_BGR 0x08 -#define ST77XX_MADCTL_MH 0x04 - -#define TFT_CASET ST7735_CASET -#define TFT_PASET ST7735_RASET -#define TFT_RAMWR ST7735_RAMWR -#define TFT_MADCTL ST7735_MADCTL - -#endif - - - -#ifdef __cplusplus - -class TFT_T_DMA -{ - public: - TFT_T_DMA(uint8_t _CS, uint8_t _DC, uint8_t _RST = 255, uint8_t _MOSI=11, uint8_t _SCLK=13, uint8_t _MISO=12, uint8_t touch_cs=38, uint8_t touch_irq=37); - - void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); - void begin(void); - void flipscreen(bool flip); - boolean isflipped(void); - void startDMA(void); - void stopDMA(); - int get_frame_buffer_size(int *width, int *height); - - // Touch screen functions - #define TOUCH_ENABLED() ((_touch_cs != 255) && (_touch_irq != 255)) - bool isTouching(void) { return ((!TOUCH_ENABLED())?false:(digitalRead(_touch_irq) == LOW)); } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax); - - // NoDMA functions - void writeScreenNoDma(const uint16_t *pcolors); - void fillScreenNoDma(uint16_t color); - void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - // DMA functions - uint16_t * getLineBuffer(int j); - void writeScreen(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int y, uint16_t *buf); - void fillScreen(uint16_t color); - void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - protected: - uint8_t _rst, _cs, _dc; - uint8_t _miso, _mosi, _sclk; - uint8_t _touch_irq=255, _touch_cs=255; - bool flipped=false; - - void wait(void); - void enableTouchIrq(); -}; - -#endif -#endif diff --git a/MCUME_teensy41/teensy800/tft_t_dma_config.h b/MCUME_teensy41/teensy800/tft_t_dma_config.h deleted file mode 100644 index 0a712da..0000000 --- a/MCUME_teensy41/teensy800/tft_t_dma_config.h +++ /dev/null @@ -1,13 +0,0 @@ -#include "platform_config.h" - -//#define ST7789 1 -//#define ILI9341 1 - -#define TFT_LINEARINT 1 -#define LINEARINT_HACK 1 - -//#define FLIP_SCREEN 1 -//#define TFT_DEBUG 1 -#if defined(__IMXRT1052__) || defined(__IMXRT1062__) -//#define TFT_STATICFB 1 -#endif diff --git a/MCUME_teensy41/teensy800/vga_t_dma.h b/MCUME_teensy41/teensy800/vga_t_dma.h deleted file mode 100644 index 81a986b..0000000 --- a/MCUME_teensy41/teensy800/vga_t_dma.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - Wrapping class to extend VGA_T4 to TFT_T_DMA -*/ - -#ifndef _VGA_T_DMAH_ -#define _VGA_T_DMAH_ - -#ifdef __cplusplus -#include -#endif - - -#define RGBVAL16(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) - - - - -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 - -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - - - -#ifdef __cplusplus - -class TFT_T_DMA: public VGA_T4 -{ - public: - // Fake touch screen functions - bool isTouching(void) { return false; } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { } - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { }; - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { } - - // fake DMA functions - void startDMA(void) { }; - void stopDMA(void) { }; - - // fake no DMA functions - void writeScreenNoDma(const vga_pixel *pcolors) { writeScreen(pcolors); } - void fillScreenNoDma(vga_pixel color) { clear(color); } - void drawTextNoDma(int16_t x, int16_t y, const char * text, vga_pixel fgcolor, vga_pixel bgcolor, bool doublesize) { drawText(x,y,text,fgcolor,bgcolor,doublesize); } - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, vga_pixel color) { drawRect(x, y, w, h, color); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap) { drawSprite(x, y, bitmap); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh) { drawSprite(x, y, bitmap, croparx, cropary, croparw, croparh); } -}; - - -#endif -#endif diff --git a/MCUME_teensy41/teensy800/atari800.c b/MCUME_teensy41/teensy800/wrapemu.c similarity index 97% rename from MCUME_teensy41/teensy800/atari800.c rename to MCUME_teensy41/teensy800/wrapemu.c index c6dc256..edb53e8 100644 --- a/MCUME_teensy41/teensy800/atari800.c +++ b/MCUME_teensy41/teensy800/wrapemu.c @@ -1,4 +1,4 @@ -#include "atari800.h" +#include "wrapemu.h" #include #include "memory.h" #include "cpu.h" @@ -18,6 +18,9 @@ #include "pokeysnd.h" #endif +#define R32(rgb) ((rgb>>16)&0xff) +#define G32(rgb) ((rgb>>8)&0xff) +#define B32(rgb) (rgb & 0xff) // Controllers typedef struct @@ -508,23 +511,23 @@ void at8_Step(void) INPUT_Frame(); // Joystick side button, trigger and directions - if (k & MASK_JOY2_BTN) + if ( (k & MASK_JOY2_BTN) || (k & MASK_JOY1_BTN) ) which->trig = 1; else which->trig = 0; - if (k & MASK_JOY2_DOWN) + if ( (k & MASK_JOY2_DOWN) || (k & MASK_JOY1_DOWN) ) which->down = 1; else which->down = 0; - if (k & MASK_JOY2_UP) + if ( (k & MASK_JOY2_UP) || (k & MASK_JOY1_UP) ) which->up = 1; else which->up = 0; - if (k & MASK_JOY2_RIGHT) + if ( (k & MASK_JOY2_LEFT) || (k & MASK_JOY1_LEFT) ) which->left = 1; else which->left = 0; - if (k & MASK_JOY2_LEFT) + if ( (k & MASK_JOY2_RIGHT) || (k & MASK_JOY1_RIGHT) ) which->right = 1; else which->right = 0; diff --git a/MCUME_teensy41/teensy800/atari800.h b/MCUME_teensy41/teensy800/wrapemu.h similarity index 100% rename from MCUME_teensy41/teensy800/atari800.h rename to MCUME_teensy41/teensy800/wrapemu.h diff --git a/MCUME_teensy41/teensy81/emuapi.cpp b/MCUME_teensy41/teensy81/emuapi.cpp index eb4be06..e128cca 100644 --- a/MCUME_teensy41/teensy81/emuapi.cpp +++ b/MCUME_teensy41/teensy81/emuapi.cpp @@ -5,25 +5,31 @@ extern "C" { #include "iopins.h" } -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#else -#include "tft_t_dma.h" -#endif +#include -#ifdef HAS_USBKEY +#ifdef HAS_USB #include "USBHost_t36.h" // Read this header first for key info USBHost myusb; USBHub hub1(myusb); +#ifdef HAS_USBKEY KeyboardController keyboard1(myusb); USBHIDParser hid1(myusb); MouseController mouse1(myusb); +#endif +#ifdef HAS_USBMIDI MIDIDevice midi1(myusb); #endif +#ifdef HAS_USBJOY +#define COUNT_JOYSTICKS 4 +JoystickController joysticks[COUNT_JOYSTICKS](myusb); +#endif +#endif static bool emu_writeConfig(void); static bool emu_readConfig(void); static bool emu_eraseConfig(void); +static bool emu_writeGfxConfig(char * display_type); +static int emu_readGfxConfig(void); static bool mouseDetected = false; static bool keyboardDetected = false; @@ -34,8 +40,9 @@ static File file; #define MAX_FILES 64 #define AUTORUN_FILENAME "autorun.txt" +#define GFX_CFG_FILENAME "gfxmode.txt" -#define MAX_FILENAME_SIZE 24 +#define MAX_FILENAME_SIZE 34 #define MAX_MENULINES 9 #define TEXT_HEIGHT 16 #define TEXT_WIDTH 8 @@ -53,7 +60,8 @@ static File file; #define MENU_VGA_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) #define MENU_VGA_YOFFSET (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37) -extern TFT_T_DMA tft; +#include "t4_dsp.h" +T4_DSP tft; static int nbFiles=0; static int curFile=0; @@ -65,6 +73,8 @@ static char selected_filename[MAX_FILENAME_SIZE]=""; static char second_selected_filename[MAX_FILENAME_SIZE]=""; static bool menuRedraw=true; static bool autorun=false; +static bool vgahires=false; + static const unsigned short * keys; #ifdef TEECOMPUTER @@ -103,7 +113,7 @@ void emu_printf(int val) void emu_printi(int val) { - Serial.println(val); + Serial.println(val,HEX); } void emu_printh(int val) @@ -158,6 +168,29 @@ void emu_Free(void * pt) free(pt); } +#define SMEMPOOL (0x800000) +EXTMEM static unsigned char slowmem[SMEMPOOL]; +static int slowmempt = 0; + +void * emu_SMalloc(unsigned int size) +{ + void * mem = (void*)&slowmem[slowmempt]; + slowmempt += size; + + if ( slowmempt > SMEMPOOL ) { + mem = NULL; + emu_printf("failure to allocate slow"); + } + else { + emu_printf("could allocate slow static "); + emu_printf(size); + } + return mem; +} + +void emu_SFree(void * pt) +{ +} /******************************** * Input and keyboard ********************************/ @@ -329,6 +362,12 @@ int emu_ReadKeys(void) #endif if ( row & 0x02 ) retval |= MASK_JOY2_BTN; + +#ifdef EXTPAD + if ( sh_pressed ) retval |= MASK_KEY_USER3; + if ( fn_pressed ) retval |= MASK_KEY_USER1; + digitalWrite(KLED, 0); +#else // Handle LED flash uint32_t time_ms=millis(); if ((time_ms-last_t_ms) > 100) { @@ -412,8 +451,9 @@ int emu_ReadKeys(void) if ( key_fn ) retval |= MASK_KEY_USER2; if ( ( key_fn ) && (keymatrix[4] == 0x10 )) retval |= MASK_KEY_USER1; +#endif - if ( (key_fn) && (key_sh) ) + if ( (fn_pressed) && (sh_pressed) ) #else if ( ((retval & (MASK_KEY_USER1+MASK_KEY_USER2)) == (MASK_KEY_USER1+MASK_KEY_USER2)) || (retval & MASK_KEY_USER4 ) ) @@ -453,8 +493,10 @@ int emu_ReadKeys(void) while (true) { ; } -#endif +#endif } + + emu_GetJoystick(); return (retval); } @@ -607,7 +649,7 @@ int emu_setKeymap(int index) { } int emu_GetMouse(int *x, int *y, int *buts) { -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBKEY) if (mouse1.available()) { *buts = mouse1.getButtons(); *x = mouse1.getMouseX(); @@ -620,7 +662,23 @@ int emu_GetMouse(int *x, int *y, int *buts) { return 0; } -#ifdef HAS_USBKEY +int emu_GetJoystick(void) { +#if defined(HAS_USB) && (HAS_USBJOY) + for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) { + if (joysticks[joystick_index].available()) { + uint64_t axis_mask = joysticks[joystick_index].axisMask(); + uint64_t axis_changed_mask = joysticks[joystick_index].axisChangedMask(); + uint32_t buttons = joysticks[joystick_index].getButtons(); + Serial.printf("Joystick(%d): buttons = %x", joystick_index, buttons); + Serial.println(); + } + } + return 1; +#endif + return 0; +} + +#if defined(HAS_USB) && (HAS_USBKEY) void OnPress(auto key) { keyboardDetected = true; @@ -764,7 +822,7 @@ int emu_KeyboardDetected(void) { return (keyboardDetected?1:0); } -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) static unsigned char midiBuffer[16]; static unsigned char midiLastCmd=0; static int midiDataCnt=0; @@ -772,8 +830,7 @@ static int midiCmdNbParam=0; #endif void emu_MidiOnDataReceived(unsigned char value) { - -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) //Serial.println(value, HEX); //10000000 = 128 = note off //10010000 = 144 = note on @@ -941,6 +998,7 @@ void emu_MidiOnDataReceived(unsigned char value) { /******************************** * Menu file loader UI ********************************/ +#ifdef FILEBROWSER static int readNbFiles(void) { int totalFiles = 0; @@ -970,8 +1028,6 @@ static int readNbFiles(void) { return totalFiles; } - - void backgroundMenu(void) { menuRedraw=true; tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00)); @@ -981,11 +1037,13 @@ void backgroundMenu(void) { int handleMenu(uint16_t bClick) { if (autorun) { + toggleMenu(false); + menuRedraw=false; return (ACTION_RUN1); } int action = ACTION_NONE; - if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) ) { + if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) || ( bClick & MASK_KEY_USER2 ) ) { char newpath[MAX_FILENAME_PATH]; strcpy(newpath, selection); strcat(newpath, "/"); @@ -996,17 +1054,31 @@ int handleMenu(uint16_t bClick) File file = SD.open(selection); if (file.isDirectory()) { curFile = 0; - nbFiles = readNbFiles(); + nbFiles = readNbFiles(); + menuRedraw=true; } - else { - action = ACTION_RUN1; + else + { #ifdef TEECOMPUTER - if (key_extmode) { + if ( (key_extmode) || ( key_sh) ) { emu_writeConfig(); } + if ( tft.getMode() < MODE_VGA_320x240) { + if ( bClick & MASK_KEY_USER2 ) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + } + //emu_SwapJoysticks(0); #endif + toggleMenu(false); + menuRedraw=false; + return (ACTION_RUN1); } - menuRedraw=true; } else if ( bClick & MASK_KEY_USER1 ) { menuRedraw=true; @@ -1015,19 +1087,14 @@ int handleMenu(uint16_t bClick) strcat(second_selection, "/"); strcat(second_selection, second_selected_filename); action = ACTION_RUN2; - } - else if ( bClick & MASK_KEY_USER2 ) { - menuRedraw=true; - //action = ACTION_RUN3; - emu_SwapJoysticks(0); - } + } else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) { if (curFile!=0) { menuRedraw=true; curFile--; } } - else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { + else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { if ((curFile-9)>=0) { menuRedraw=true; curFile -= 9; @@ -1042,7 +1109,7 @@ int handleMenu(uint16_t bClick) menuRedraw=true; } } - else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { + else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { if ((curFile<(nbFiles-9)) && (nbFiles)) { curFile += 9; menuRedraw=true; @@ -1099,12 +1166,12 @@ int handleMenu(uint16_t bClick) return (action); } -bool menuActive(void) +int menuActive(void) { - return (menuOn); + return (menuOn?1:0); } -void toggleMenu(bool on) { +void toggleMenu(int on) { if (on) { menuOn=true; backgroundMenu(); @@ -1122,7 +1189,7 @@ char * menuSecondSelection(void) { return (second_selection); } - +#endif /******************************** * OSKB handling @@ -1140,8 +1207,9 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) char c[4] = {' ',0,' ',0}; const char * cpt = str; int i=0; - int fb_width,fb_height; - tft.get_frame_buffer_size(&fb_width, &fb_height); + int fb_width,fb_height,fbstride; + + fbstride = tft.get_frame_buffer_size(&fb_width, &fb_height); int ypos = (bottom?(fb_height-2*8):0); int line = row + (bottom?2:0); while ((c[1] = *cpt++)) @@ -1150,7 +1218,7 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0); else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff); if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff); - tft.drawTextNoDma(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); + tft.drawText(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); i++; } } @@ -1248,7 +1316,7 @@ int handleOSKB(void) { return retval; } -void toggleOSKB(bool forceon) { +void toggleOSKB(int forceon) { if (forceon) { oskbOn = true; drawOSKB(); @@ -1332,6 +1400,17 @@ int emu_FileRead(void * buf, int size, int handler) #endif } +int emu_FileWrite(void * buf, int size, int handler) +{ +// emu_printf("emu_FileWrite"); +// emu_printi(handler); +#ifdef HCFH + return (file.write(buf, size)); +#else + return (getFileHandler(handler).write(buf, size)); +#endif +} + int emu_FileGetc(int handler) { // emu_printf("FileGetc"); // emu_printi(handler); @@ -1404,6 +1483,9 @@ unsigned int emu_FileSize(const char * filepath) emu_printf(filesize); lofile.close(); } + else { + emu_printf("filesize failed"); + } return(filesize); } @@ -1489,6 +1571,48 @@ static bool emu_eraseConfig(void) SD.remove (ROMSDIR "/" AUTORUN_FILENAME); } +static bool emu_writeGfxConfig(char * display_type) +{ + bool retval = false; + SD.remove ("/" GFX_CFG_FILENAME); + if (strcmp(display_type, "VGA")) { + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(display_type, strlen(display_type)) != strlen(display_type)) { + emu_printf("GFX config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + } + return retval; +} + +#define CFG_VGA 0 +#define CFG_ILI 1 +#define CFG_ST 2 + +static int emu_readGfxConfig(void) +{ + int retval = CFG_VGA; // No file = VGA + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + if (filesize == 2) // "ST" + { + retval = CFG_ST; + } + else if (filesize == 3) // "ILI" + { + retval = CFG_ILI; + } + lofile.close(); + } + return retval; +} + /******************************** * File IO compatibility ********************************/ @@ -1670,62 +1794,249 @@ FRESULT f_mkdir (const char* path) /******************************** - * Initialization + * GFX wrapper ********************************/ -void emu_init(void) +static unsigned short palette16[PALETTE_SIZE]; +static IntervalTimer myTimer; +volatile boolean vbl=true; +volatile boolean vgatimervsync=false; +static void (*vblCallback)(void) = nullptr; +static int skip=0; + +static void vblCount() { + if (vbl) { + vbl = false; + } else { + vbl = true; + } +} + +void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) +{ + if (index= MODE_VGA_320x240 ) { + if (vgatimervsync) { + while (vbl==vb) {}; + } + else { + tft.waitSync(); + } + } + else { + while (vbl==vb) {}; + } + if (vblCallback != nullptr) { + vblCallback(); + } +} + +void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride) +{ + if (skip == 0) { + tft.writeScreenPal(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); + } +} +void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLinePal(width,height,line, VBuf, palette16); + } +} + +void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine(width,height,line, VBuf); + } +} + +void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine8(width,height,line, VBuf, palette16); + } +} + +int emu_IsVga(void) +{ + return (tft.getMode() >= MODE_VGA_320x240?1:0); +} + +int emu_IsVgaHires(void) +{ + return (tft.getMode() >= MODE_VGA_640x240?1:0); +} + +int emu_FrameSkip(void) +{ + return skip; +} + + +/******************************** + * AUDIO wrapper +********************************/ +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +AudioPlaySystem mymixer; + +void emu_sndInit() { + Serial.println("sound init"); + mymixer.begin_audio(256, mymixer.snd_Mixer); + mymixer.start(); +} + +void emu_sndPlaySound(int chan, int volume, int freq) +{ + if (chan < 6) { + mymixer.sound(chan, freq, volume); + } + /* + Serial.print(chan); + Serial.print(":" ); + Serial.print(volume); + Serial.print(":" ); + Serial.println(freq); + */ +} + +void emu_sndPlayBuzz(int size, int val) { + mymixer.buzz(size,val); + //Serial.print((val==1)?1:0); + //Serial.print(":"); + //Serial.println(size); +} +#endif + +/******************************** + * Initialization +********************************/ +void emu_init(int hires) { Serial.begin(115200); + vgahires = hires; -#ifdef HAS_USBKEY +#ifdef HAS_USB myusb.begin(); +#ifdef HAS_USBKEY keyboard1.attachPress(OnPress); keyboard1.attachRelease(OnRelease); #endif +#endif - while (!SD.begin(SD_CS)) +#ifdef FILEBROWSER + if (!SD.begin(SD_CS)) { - Serial.println("SD begin failed, retrying..."); - delay(1000); + Serial.println("No SD card detected"); } strcpy(selection,ROMSDIR); - FileHandlersInit(); - nbFiles = readNbFiles(); - - Serial.print("SD initialized, files found: "); Serial.println(nbFiles); +#endif emu_InitJoysticks(); #ifdef SWAP_JOYSTICK - joySwapped = true; + joySwapped = true; #else - joySwapped = false; + joySwapped = false; #endif -#ifdef TEECOMPUTER -#ifndef HAS_T4_VGA - tft.flipscreen(false); -#endif -#endif int keypressed = emu_ReadKeys(); +#ifdef HAS_T4_VGA + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } +#else + int gfx_mode = CFG_VGA; // default +#ifdef FILEBROWSER + gfx_mode = emu_readGfxConfig(); +#endif + // Force VGA if UP pressed + if (keypressed & MASK_JOY2_UP) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("VGA"); +#endif + gfx_mode = CFG_VGA; + } + else { + if (keypressed & MASK_JOY2_LEFT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ST"); +#endif + gfx_mode = CFG_ST; + } + else if (keypressed & MASK_JOY2_RIGHT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ILI"); +#endif + gfx_mode = CFG_ILI; + } + } + if (gfx_mode == CFG_VGA) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + else + { + tft.begin(gfx_mode == CFG_ILI?MODE_TFTILI_320x240:MODE_TFTST_320x240); + } +#endif + if (keypressed & MASK_JOY2_DOWN) { tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) ); tft.drawTextNoDma(64,48, (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); +#ifdef FILEBROWSER emu_eraseConfig(); delay(1000); +#endif } else { +#ifdef FILEBROWSER if (emu_readConfig()) { autorun = true; } +#endif } +#ifdef FILEBROWSER toggleMenu(true); +#endif } -void emu_start(void) +void emu_start(int vblms, void * callback, int forcetimervsync) { + vgatimervsync = forcetimervsync?true:false; + tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); + tft.startRefresh(); + if (callback != nullptr) { + vblCallback = callback; + } + + myTimer.begin(vblCount, vblms); +#ifdef HAS_SND + emu_sndInit(); +#endif usbnavpad = 0; } diff --git a/MCUME_teensy41/teensy81/emuapi.h b/MCUME_teensy41/teensy81/emuapi.h index 3293486..5dd6130 100644 --- a/MCUME_teensy41/teensy81/emuapi.h +++ b/MCUME_teensy41/teensy81/emuapi.h @@ -2,123 +2,14 @@ #define EMUAPI_H #include "platform_config.h" - -//#define TIMER_REND 1 -#define EXTRA_HEAP 0x10 - -// Title: < > -#define TITLE " ZX81/ZX80 Emulator" -#define ROMSDIR "z81" - -#define emu_Init(ROM) {z81_Start(ROM); z81_Init(); } -#define emu_Step(x) {z81_Step();} -#define emu_Input(x) {z81_Input(x);} - -#define MAX_FILENAME_PATH 64 -#define NB_FILE_HANDLER 4 -#define PALETTE_SIZE 2 -#define VID_FRAME_SKIP 0x0 -#define TFT_VBUFFER_YCROP 0 -#define SINGLELINE_RENDERING 1 - -#define R32(rgb) ((rgb>>16)&0xff) -#define G32(rgb) ((rgb>>8)&0xff) -#define B32(rgb) (rgb & 0xff) +#include "emucfg.h" #define ACTION_NONE 0 -#define ACTION_MAXKBDVAL 16 -#define ACTION_EXITKBD 128 -#define ACTION_RUN1 129 -#define ACTION_RUN2 130 -#define ACTION_RUN3 131 - -#ifdef KEYMAP_PRESENT - -#define keylables_map0_0 (char *)"qwertyuiop\x1a" -#define keylables_map0_1 (char *)" asdfghjkl\x19" -#define keylables_map0_2 (char *)" zxcvbnm,.;/" -#define keylables_map0_3 (char *)" +\x10-" -const unsigned short key_map0[] = { - 'q','w','e','r','t','y','u','i','o','p',127, //lowecase - 0,'a','s','d','f','g','h','j','k','l',10, - 0,'z','x','c','v','b','n','m',',','.',';','/', - 0,0,0,0, - 0,'+',' ','-' - }; - -#define keylables_map1_0 (char *)" \x1a" -#define keylables_map1_1 (char *)" \x19" -#define keylables_map1_2 (char *)" <>:?" -#define keylables_map1_3 (char *)" =\x10 " -const unsigned short key_map1[] = { - '1','2','3','4','5','6','7','8','9','0',127, // digit keys - 0, 0,0,0,0,0,0,0,0,0,10, - 0, 0,0,0,0,0,0,0,'<','>',':','?', - 154,152,151,153, //U L R D - 0,'=',' ',0 - }; - -#define keylables_map2_0 (char *)" \" $ *()\x1a" -#define keylables_map2_1 (char *)" \x19" -#define keylables_map2_2 (char *)" <>:?" -#define keylables_map2_3 (char *)" =\x10 " -const unsigned short key_map2[] = { - 0,'"',0,'$',0,0,0,'*','(',')',127, // shiftothers - 0, 0,0,0,0,0,0,0,0,0,10, - 0, 0,0,0,0,0,0,0,'<','>',':','?', - 154,152,151,153, //U L R D - 0,'=',' ',0 - }; - -#define keylables_map3_0 (char *)"1234567890 " -#define keylables_map3_1 (char *)" " -#define keylables_map3_2 (char *)" " -#define keylables_map3_3 (char *)" " - -const unsigned short key_map3[] = { - '1','2','3','4','5','6','7','8','9','0',0, // digit keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 154,152,151,153, //U L R D - 0,0,' ',0 - }; - -#define keylables_map4_0 (char *)" " -#define keylables_map4_1 (char *)" " -#define keylables_map4_2 (char *)" " -#define keylables_map4_3 (char *)" " - -const unsigned short key_map4[] = { - 0,0,0,0,0,0,0,0,0,0,0, // function keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 154,152,151,153, //U L R D - 0,0,' ',0 - }; - -#define keylables_map5_0 (char *)" " -#define keylables_map5_1 (char *)" " -#define keylables_map5_2 (char *)" " -#define keylables_map5_3 (char *)" " - -const unsigned short key_map5[] = { - 0,0,0,0,0,0,0,0,0,0,0, // extra keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 154,152,151,153, //U L R D - 0,0,' ',0 - }; - -const unsigned short matkeys[] = { - 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 - 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 - 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 - 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN - 0x510,0x010,0x110,0x310, // row 4 - }; - -#endif +#define ACTION_RUN1 1 +#define ACTION_RUN2 2 +#define FORCE_VGATIMERVSYNC 1 +#define SUPPORT_HIRES 1 #define MASK_JOY2_RIGHT 0x0001 #define MASK_JOY2_LEFT 0x0002 @@ -135,24 +26,25 @@ const unsigned short matkeys[] = { #define MASK_JOY1_BTN 0x1000 #define MASK_KEY_USER4 0x2000 +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) #ifdef __cplusplus extern "C" { -#else -#define bool unsigned char +extern void emu_init(int hires=0); +extern void emu_start(int vblms, void * callback, int forcetimervsync=0); #endif - -extern void emu_init(void); -extern void emu_start(void); extern void emu_printf(const char * text); extern void emu_printi(int val); extern void emu_printh(int val); extern void * emu_Malloc(unsigned int size); extern void * emu_MallocI(unsigned int size); extern void emu_Free(void * pt); +extern void * emu_SMalloc(unsigned int size); +extern void emu_SFree(void * pt); extern int emu_FileOpen(const char * filepath, const char * mode); extern int emu_FileRead(void * buf, int size, int handler); +extern int emu_FileWrite(void * buf, int size, int handler); extern int emu_FileGetc(int handler); extern int emu_FileSeek(int handler, int seek, int origin); extern int emu_FileTell(int handler); @@ -163,24 +55,23 @@ extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size); extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek); extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index); -extern void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride); -extern void emu_DrawLine(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line); extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line); +extern void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride); extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line); -extern void emu_CopyLine(int width, int height, int ysrc, int ydst); extern void emu_DrawVsync(void); extern int emu_FrameSkip(void); -extern void * emu_LineBuffer(int line); -extern void emu_tweakVideo(int shiftdelta, int numdelta, int denomdelta); +extern int emu_IsVga(void); +extern int emu_IsVgaHires(void); -extern bool menuActive(void); +extern int menuActive(void); extern char * menuSelection(void); extern char * menuSecondSelection(void); -extern void toggleMenu(bool on); +extern void toggleMenu(int on); extern int handleMenu(unsigned short bClick); extern int handleOSKB(void); -extern void toggleOSKB(bool forceon); +extern void toggleOSKB(int forceon); extern void emu_InitJoysticks(void); extern int emu_SwapJoysticks(int statusOnly); @@ -189,6 +80,7 @@ extern int emu_ReadKeys(void); extern int emu_GetPad(void); extern int emu_GetMouse(int *x, int *y, int *buts); extern int emu_MouseDetected(void); +extern int emu_GetJoystick(void); extern int emu_KeyboardDetected(void); extern int emu_ReadAnalogJoyX(int min, int max); extern int emu_ReadAnalogJoyY(int min, int max); diff --git a/MCUME_teensy41/teensy81/emucfg.h b/MCUME_teensy41/teensy81/emucfg.h new file mode 100644 index 0000000..b08bfaf --- /dev/null +++ b/MCUME_teensy41/teensy81/emucfg.h @@ -0,0 +1,115 @@ +#ifndef EMUCFG_H +#define EMUCFG_H + +#include "wrapemu.h" + +// Title: < > +#define TITLE " ZX81/ZX80 Emulator" +#define ROMSDIR "z81" + +#define emu_Init(ROM) {z81_Start(ROM); z81_Init(); } +#define emu_Step(x) {z81_Step();} +#define emu_Input(x) {z81_Input(x);} + +#define MAX_FILENAME_PATH 64 +#define NB_FILE_HANDLER 4 + +#define PALETTE_SIZE 2 +#define VID_FRAME_SKIP 0x0 +#define TFT_VBUFFER_YCROP 0 +#define SINGLELINE_RENDERING 1 +//#define CUSTOM_SND 1 +//#define TIMER_REND 1 +//#define EXTPAD 1 +#define EXTRA_HEAP 0x10 +#define FILEBROWSER 1 + + +#ifdef KEYMAP_PRESENT + +#define keylables_map0_0 (char *)"qwertyuiop\x1a" +#define keylables_map0_1 (char *)" asdfghjkl\x19" +#define keylables_map0_2 (char *)" zxcvbnm,.;/" +#define keylables_map0_3 (char *)" +\x10-" +const unsigned short key_map0[] = { + 'q','w','e','r','t','y','u','i','o','p',127, //lowecase + 0,'a','s','d','f','g','h','j','k','l',10, + 0,'z','x','c','v','b','n','m',',','.',';','/', + 0,0,0,0, + 0,'+',' ','-' + }; + +#define keylables_map1_0 (char *)" \x1a" +#define keylables_map1_1 (char *)" \x19" +#define keylables_map1_2 (char *)" <>:?" +#define keylables_map1_3 (char *)" =\x10 " +const unsigned short key_map1[] = { + '1','2','3','4','5','6','7','8','9','0',127, // digit keys + 0, 0,0,0,0,0,0,0,0,0,10, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 154,152,151,153, //U L R D + 0,'=',' ',0 + }; + +#define keylables_map2_0 (char *)" \" $ *()\x1a" +#define keylables_map2_1 (char *)" \x19" +#define keylables_map2_2 (char *)" <>:?" +#define keylables_map2_3 (char *)" =\x10 " +const unsigned short key_map2[] = { + 0,'"',0,'$',0,0,0,'*','(',')',127, // shiftothers + 0, 0,0,0,0,0,0,0,0,0,10, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 154,152,151,153, //U L R D + 0,'=',' ',0 + }; + +#define keylables_map3_0 (char *)"1234567890 " +#define keylables_map3_1 (char *)" " +#define keylables_map3_2 (char *)" " +#define keylables_map3_3 (char *)" " + +const unsigned short key_map3[] = { + '1','2','3','4','5','6','7','8','9','0',0, // digit keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 154,152,151,153, //U L R D + 0,0,' ',0 + }; + +#define keylables_map4_0 (char *)" " +#define keylables_map4_1 (char *)" " +#define keylables_map4_2 (char *)" " +#define keylables_map4_3 (char *)" " + +const unsigned short key_map4[] = { + 0,0,0,0,0,0,0,0,0,0,0, // function keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 154,152,151,153, //U L R D + 0,0,' ',0 + }; + +#define keylables_map5_0 (char *)" " +#define keylables_map5_1 (char *)" " +#define keylables_map5_2 (char *)" " +#define keylables_map5_3 (char *)" " + +const unsigned short key_map5[] = { + 0,0,0,0,0,0,0,0,0,0,0, // extra keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 154,152,151,153, //U L R D + 0,0,' ',0 + }; + +const unsigned short matkeys[] = { + 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 + 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 + 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 + 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN + 0x510,0x010,0x110,0x310, // row 4 + }; + +#endif + +#endif diff --git a/MCUME_teensy41/teensy81/platform_config.h b/MCUME_teensy41/teensy81/platform_config.h index a27370c..914d152 100644 --- a/MCUME_teensy41/teensy81/platform_config.h +++ b/MCUME_teensy41/teensy81/platform_config.h @@ -4,13 +4,13 @@ #define TEECOMPUTER 1 #ifdef TEECOMPUTER -//#define ILI9341 1 -//#define ST7789 1 -//#define TFTSPI1 1 -#define HAS_T4_VGA 1 +#define TFTSPI1 1 +//#define HAS_T4_VGA 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 -#define INVX 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 #define PT8211 1 #else @@ -19,7 +19,11 @@ //#define INVX 1 #define INVY 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 +#define PT8211 1 #endif diff --git a/MCUME_teensy41/teensy81/t4_dsp.cpp b/MCUME_teensy41/teensy81/t4_dsp.cpp new file mode 100644 index 0000000..43301fa --- /dev/null +++ b/MCUME_teensy41/teensy81/t4_dsp.cpp @@ -0,0 +1,1774 @@ +/* + TFT/VGA driver + DMA TFT driver based on C64 ILI9341 dma driver from Frank Bösing, 2017 +*/ + +#include "T4_DSP.h" + +#include +#include + +#include "font8x8.h" + +// TFT constants and variables +#define TFT_LINEARINT 1 +#define LINEARINT_HACK 1 +#define DMA_LINES_PER_BLOCK 64 +#define DMA_NUM_SETTINGS 4 + +#define TFT_SWRESET 0x01 +#define TFT_SLPOUT 0x11 +#define TFT_INVON 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_MADCTL 0x36 +#define TFT_PIXFMT 0x3A +#define TFT_MADCTL_MY 0x80 +#define TFT_MADCTL_MX 0x40 +#define TFT_MADCTL_MV 0x20 +#define TFT_MADCTL_ML 0x10 +#define TFT_MADCTL_RGB 0x00 +#define TFT_MADCTL_BGR 0x08 +#define TFT_MADCTL_MH 0x04 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) +//#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) +//#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) +//#define R16(rgb) ((rgb>>8)&0xf8) +//#define G16(rgb) ((rgb>>3)&0xfc) +//#define B16(rgb) ((rgb<<3)&0xf8) + +// LPSPI4 = SPI0 in Teensy 4.0 +// LPSPI3 = SPI1 in Teensy 4.0 +// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) + +#ifdef TFTSPI1 +#define SPI SPI1 +#define LPSPIP_TDR LPSPI3_TDR +#define LPSPIP_CR LPSPI3_CR +#define LPSPIP_CFGR1 LPSPI3_CFGR1 +#define LPSPIP_TCR LPSPI3_TCR +#define LPSPIP_DER LPSPI3_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX +#else +#define LPSPIP_TDR LPSPI4_TDR +#define LPSPIP_CR LPSPI4_CR +#define LPSPIP_CFGR1 LPSPI4_CFGR1 +#define LPSPIP_TCR LPSPI4_TCR +#define LPSPIP_DER LPSPI4_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX +#endif + +#define SPICLOCK 60000000 +#define SPI_MODE SPI_MODE0 + +// VGA constants and macros +typedef uint8_t vga_pixel; +#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) + +static DMASetting dmasettings[DMA_NUM_SETTINGS]; +static DMAChannel dmatx; +static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K +static volatile uint8_t rstop = 0; +static volatile bool cancelled = false; +static volatile uint8_t curTransfer = 0; +static uint8_t nbTransfer = 0; +static uint16_t * tft_buffer; +static int tft_width; +static int tft_height; +static int tft_stride; + +#define DELAY_MASK 0x80 +PROGMEM static const uint8_t init_commands[] = { + 1+DELAY_MASK, TFT_SWRESET, 150, + 1+DELAY_MASK, TFT_SLPOUT, 255, + 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, + 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, + 1, TFT_INVON, + 1, TFT_DISPON, + 0 +}; + +// VGA constants and variables +// Objective: +// generates VGA signal fully in hardware with as little as possible CPU help + +// Principle: +// QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) +// 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate +// RGB out, combined to create 8bits(/12bits) output. + +// Note: +// - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels +// - experimental resolution: 352x240,352x480 +// - experimental resolution: 512x240,512x480 (not stable) +// - video memory is allocated using malloc in T4 heap +// - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing +// but tried to be compensated by pixel shifting +// - Default is 8bits RRRGGGBB (332) +// But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! +// - Only ok at 600MHz else some disturbances visible + + + +#define TOP_BORDER 40 +#define PIN_HBLANK 15 + +#define PIN_R_B2 33 +#define PIN_R_B1 4 +#define PIN_R_B0 3 +#define PIN_G_B2 2 +#define PIN_G_B1 13 +#define PIN_G_B0 11 +#define PIN_B_B1 12 +#define PIN_B_B0 10 + + +#define DMA_HACK 0x80 + +#define R16(rgb) ((rgb>>8)&0xf8) +#define G16(rgb) ((rgb>>3)&0xfc) +#define B16(rgb) ((rgb<<3)&0xf8) + +// VGA 640x480@60Hz +// Screen refresh rate 60 Hz +// Vertical refresh 31.46875 kHz +// Pixel freq. 25.175 MHz +// +// Visible area 640 25.422045680238 us +// Front porch 16 0.63555114200596 us +// Sync pulse 96 3.8133068520357 us +// Back porch 48 1.9066534260179 us +// Whole line 800 31.777557100298 us + +#define frame_freq 60.0 // Hz +#define line_freq 31.46875 // KHz +#define pix_freq (line_freq*800) // KHz (25.175 MHz) + +// pix_period = 39.7ns +// H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) +#define frontporch_pix 20 //16 +#define backporch_pix 44 //48 + +// Flexio Clock +// PLL3 SW CLOCK (3) => 480 MHz +// PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) +#define FLEXIO_CLK_SEL_PLL3 3 +#define FLEXIO_CLK_SEL_PLL5 2 + +/* Set video PLL */ +// There are /1, /2, /4, /8, /16 post dividers for the Video PLL. +// The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, +// and CCM_ANALOG_MISC2 register sets according to the following equation. +// PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + +// nfact: +// This field controls the PLL loop divider. +// Valid range for DIV_SELECT divider value: 27~54. + +#define POST_DIV_SELECT 2 + +// Full buffer including back/front porch +static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; +static uint32_t dstbuffer __attribute__((aligned(32))); + +// Visible vuffer +static vga_pixel * vga_buffer; +static int vga_width; +static int vga_height; +static int vga_stride; + +static int maxpixperline; +static int left_border; +static int right_border; +static int line_double; +static int pix_shift; +static int ref_div_select; +static int ref_freq_num; +static int ref_freq_denom; +static int ref_pix_shift; +static int combine_shiftreg; + +#ifdef DEBUG +static uint32_t ISRTicks_prev = 0; +volatile uint32_t ISRTicks = 0; +#endif + +uint8_t T4_DSP::_rst; +uint8_t T4_DSP::_cs; +uint8_t T4_DSP::_dc; +uint8_t T4_DSP::_mosi; +uint8_t T4_DSP::_sclk; +uint8_t T4_DSP::_vsync_pin = -1; +DMAChannel T4_DSP::flexio1DMA; +DMAChannel T4_DSP::flexio2DMA; + +static volatile uint32_t VSYNC = 0; +static volatile uint32_t currentLine=0; +#define NOP asm volatile("nop\n\t"); +static gfx_mode_t gfxmode = MODE_UNDEFINED; + + +FASTRUN void T4_DSP::TFT_isr(void) { + dmatx.clearInterrupt(); + curTransfer++; + if (curTransfer >= nbTransfer) { + curTransfer = 0; + if (cancelled) { + dmatx.disable(); + rstop = 1; + } + } + arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); +} + +FASTRUN void T4_DSP::QT3_isr(void) { + TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); + TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); + + cli(); + + // V-PULSE + if (currentLine > 0) { + digitalWrite(_vsync_pin, 1); + VSYNC = 0; + } else { + digitalWrite(_vsync_pin, 0); + VSYNC = 1; + } + + currentLine++; + currentLine = currentLine % 525; + + + uint32_t y = (currentLine - TOP_BORDER) >> line_double; + // Visible area + + if (y >= 0 && y < vga_height) { + // Disable DMAs + //DMA_CERQ = flexio2DMA.channel; + //DMA_CERQ = flexio1DMA.channel; + + // Setup source adress + // Aligned 32 bits copy + unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; + flexio2DMA.TCD->SADDR = p; + if (pix_shift & DMA_HACK) + { + // Unaligned copy + uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; + flexio1DMA.TCD->SADDR = p2; + } + else { + p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 + flexio1DMA.TCD->SADDR = p; + } + + // Enable DMAs + //flexio2DMA.enable(); + //flexio1DMA.enable(); + DMA_SERQ = flexio2DMA.channel; + DMA_SERQ = flexio1DMA.channel; + arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); + } + sei(); + +#ifdef DEBUG + ISRTicks++; +#endif + asm volatile("dsb"); +} + +static void setDmaStruct() { + uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; + uint16_t * fb = (uint16_t*)malloc(remaining); + tft_buffer = fb; + tft_width = TFT_WIDTH; + tft_height = TFT_HEIGHT; + tft_stride = TFT_WIDTH; + uint16_t col=RGBVAL16(0x00,0x00,0x00); + int i=0; + while (remaining > 0) { + int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); + blocks[i] = fb; + for (int j=0;jATTR_DST = 1; + dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); + dmasettings[i].interruptAtCompletion(); + fb += len/2; + remaining -= len; + i++; + } + dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); + nbTransfer = i; +} + +static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 +{ +//if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; + CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE + | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 + | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); + CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; + CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock + const int div_post_pll = 1; // other values: 2,4 + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass +} + +T4_DSP::T4_DSP() +{ + _cs = TFT_CS; + _dc = TFT_DC; + _rst = TFT_RST; + _mosi = TFT_MOSI; + _sclk = TFT_SCLK; + pinMode(_dc, OUTPUT); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, 1); + digitalWrite(_dc, 1); + _vsync_pin = 8; +} + + +void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { + int dx=0; + int dy=0; + digitalWrite(_dc, 0); + SPI.transfer(TFT_CASET); + digitalWrite(_dc, 1); + SPI.transfer16(x1+dx); + digitalWrite(_dc, 1); + SPI.transfer16(x2+dx); + digitalWrite(_dc, 0); + SPI.transfer(TFT_PASET); + digitalWrite(_dc, 1); + SPI.transfer16(y1+dy); + digitalWrite(_dc, 1); + SPI.transfer16(y2+dy); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + return; +} + +void T4_DSP::tft_setup(bool isST) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + // RESET if reset pin defined + if (_rst != 0xff) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + const uint8_t *addr = init_commands; + uint8_t count; + digitalWrite(_cs, 0); + while (count = *addr++) { + uint8_t command = *addr++; + if ( (command == TFT_INVON) && (!isST) ) { + // Skip TFT_INVON for ILI + } + else { + digitalWrite(_dc, 0); // command + SPI.transfer(command); + uint16_t ms = count & DELAY_MASK; + count &= ~DELAY_MASK; + while (--count > 0) { // data + uint8_t data = *addr++; + if ( (command == TFT_MADCTL) && (isST) ) { + data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; + } + digitalWrite(_dc, 1); + SPI.transfer(data); + } + if (ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + digitalWrite(_cs, 1); + SPI.endTransaction(); + delay(2); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + } + } + } + digitalWrite(_cs, 1); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + SPI.endTransaction(); + /* + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_dc, 0); + digitalWrite(_cs, 0); + SPI.transfer(TFT_MADCTL); + digitalWrite(_dc, 1); + SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); + // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); + digitalWrite(_cs, 1); + SPI.endTransaction(); + */ + cancelled = false; +} + +// display VGA image +gfx_error_t T4_DSP::begin(gfx_mode_t mode) +{ + uint32_t flexio_clock_div; + combine_shiftreg = 0; +// int div_select = 49; +// int num = 135; +// int denom = 100; + int div_select = 20; + int num = 9800; + int denom = 10000; + int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; + int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; + set_videoClock(div_select,num,denom,true); + +#ifdef DEBUG + Serial.println(mode); + Serial.println("mode"); +#endif + + switch(mode) + { + case MODE_TFTILI_320x240: +#ifdef DEBUG + Serial.println("TFTILI_320x240"); +#endif + tft_setup(false); + gfxmode = mode; + break; + case MODE_TFTST_320x240: +#ifdef DEBUG + Serial.println("TFTST_320x240"); +#endif + tft_setup(true); + gfxmode = mode; + break; + + case MODE_VGA_320x240: +#ifdef DEBUG + Serial.println("VGA_320x240"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_320x480: +#ifdef DEBUG + Serial.println("VGA_320x480"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_640x240: +#ifdef DEBUG + Serial.println("VGA_640x240"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/pix_freq; + line_double = 1; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_640x480: +#ifdef DEBUG + Serial.println("VGA_640x480"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = (flexio_freq/pix_freq); + line_double = 0; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_512x240: +#ifdef DEBUG + Serial.println("VGA_512x240"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 1; + pix_shift = 0; + break; + + case MODE_VGA_512x480: +#ifdef DEBUG + Serial.println("VGA_512x480"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 0; + pix_shift = 0; + break; + + case MODE_VGA_352x240: +#ifdef DEBUG + Serial.println("VGA_352x240"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_352x480: +#ifdef DEBUG + Serial.println("VGA_352x480"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + } + + if (mode >= MODE_VGA_320x240) + { + if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { + fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); + digitalWrite(_cs, 0); + digitalWrite(_dc, 0); + SPI.transfer(TFT_DISPOFF); + digitalWrite(_cs, 1); + delay(20); + digitalWrite(_cs, 0); + digitalWrite(_cs, 1); + } + gfxmode = mode; + + maxpixperline = vga_stride; + // Save param for tweek adjustment + ref_div_select = div_select; + ref_freq_num = num; + ref_freq_denom = denom; + ref_pix_shift = pix_shift; + +#ifdef DEBUG + Serial.println("frequency"); + Serial.println(flexio_freq); + Serial.println("div"); + Serial.println(flexio_freq/pix_freq); +#endif + + pinMode(_vsync_pin, OUTPUT); + pinMode(PIN_HBLANK, OUTPUT); + + /* Basic pin setup FlexIO1 */ + pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 + pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 + pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 + pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 + /* Basic pin setup FlexIO2 */ + pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 + pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 + pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 + pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 + + /* High speed and drive strength configuration */ + *(portControlRegister(PIN_G_B2)) = 0xFF; + *(portControlRegister(PIN_R_B0)) = 0xFF; + *(portControlRegister(PIN_R_B1)) = 0xFF; + *(portControlRegister(PIN_R_B2)) = 0xFF; + *(portControlRegister(PIN_B_B0)) = 0xFF; + *(portControlRegister(PIN_B_B1)) = 0xFF; + *(portControlRegister(PIN_G_B0)) = 0xFF; + *(portControlRegister(PIN_G_B1)) = 0xFF; + + /* Set clock for FlexIO1 and FlexIO2 */ + CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) + | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); + CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) + | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); + + + /* Set up pin mux FlexIO1 */ + *(portConfigRegister(PIN_G_B2)) = 0x14; + *(portConfigRegister(PIN_R_B0)) = 0x14; + *(portConfigRegister(PIN_R_B1)) = 0x14; + *(portConfigRegister(PIN_R_B2)) = 0x14; + /* Set up pin mux FlexIO2 */ + *(portConfigRegister(PIN_B_B0)) = 0x14; + *(portConfigRegister(PIN_B_B1)) = 0x14; + *(portConfigRegister(PIN_G_B0)) = 0x14; + *(portConfigRegister(PIN_G_B1)) = 0x14; + + /* Enable the clock */ + CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + /* Enable the FlexIO with fast access */ + FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + + uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; + uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; + + /* Shifter 0 registers for FlexIO2 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 + inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter + stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled + startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable + timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 + timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock + pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output + pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity + shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode + /* Shifter 0 registers for FlexIO1 */ + FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + /* Shifter 0 registers for FlexIO1 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 + FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + if (combine_shiftreg) { + pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled + FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + } + /* Timer 0 registers for FlexIO2 */ + timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset + timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output + timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset + timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare + timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert + stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled + startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled + if (combine_shiftreg) { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag + } + else { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag + } + triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low + triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected + pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled + //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 + //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high + timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode + // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) + + int shifts_per_transfer; + if (combine_shiftreg) { + shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 + } + else { + shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 + } + FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); + /* Timer 0 registers for FlexIO1 */ + FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); +#ifdef DEBUG + Serial.println("FlexIO setup complete"); +#endif + + /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ + if (combine_shiftreg) { + FLEXIO2_SHIFTSDEN |= (1<<1); + FLEXIO1_SHIFTSDEN |= (1<<1); + } + else { + FLEXIO2_SHIFTSDEN |= (1<<0); + FLEXIO1_SHIFTSDEN |= (1<<0); + } + /* Disable DMA channel so it doesn't start transferring yet */ + flexio1DMA.disable(); + flexio2DMA.disable(); + /* Set up DMA channel to use Shifter 0 trigger */ + flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); + flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); + + + if (combine_shiftreg) { + flexio2DMA.TCD->NBYTES = 8; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 8; + flexio2DMA.TCD->CITER = maxpixperline / 8; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + flexio1DMA.TCD->NBYTES = 8; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 8; + flexio1DMA.TCD->CITER = maxpixperline / 8; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Setup DMA2 Flexio2 copy + flexio2DMA.TCD->NBYTES = 4; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 4; + flexio2DMA.TCD->CITER = maxpixperline / 4; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + // Setup DMA1 Flexio1 copy + // Use pixel shift to avoid color smearing? + if (pix_shift & DMA_HACK) + { + if (pix_shift & 0x3 == 0) { + // Aligned 32 bits copy (32bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Unaligned (source) 32 bits copy (8bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 1; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion + } + } + else + { + // Aligned 32 bits copy + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + } + +#ifdef DEBUG + Serial.println("DMA setup complete"); +#endif + + // enable clocks for QTIMER3: generates the 15KHz for hsync + // Pulse: + // low : 3.8133 us => 569x6.7ns + // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) + // (OLD TEST) + // (4us low, 28us high => 32us) + // (597x6.7ns for 4us) + // (4179x6.7ns for 28us) + CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 + //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 + + #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz + #define MARGIN_D 1000 + + TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer + // Invert output pin as we want the interupt on rising edge + TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) + TMR3_CNTR3 = 0; + TMR3_LOAD3 = 0; + + /* Inverted timings */ + unsigned long long cpu_freq = F_CPU; + unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; + int rate2 = rate; + + int substract = 1; + if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { + substract=5; + rate2=1652; + } + + #ifdef DEBUG + Serial.print("MARGIN_N is: "); + Serial.println(rate2, DEC); + Serial.print("SUBSTRACT is: "); + Serial.println(substract, DEC); +#endif + TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; + TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; + /* + TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; + */ + TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on + TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), + // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) + //configure Teensy pin Compare output + IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 + attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function + NVIC_ENABLE_IRQ(IRQ_QTIMER3); +#ifdef DEBUG + Serial.println("QTIMER3 setup complete"); + Serial.print("V-PIN is "); + Serial.println(_vsync_pin); +#endif + + /* initialize gfx buffer */ + if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift + if (gfxbuffer == NULL) return(GFX_ERROR); +#ifdef DEBUG + Serial.println("Memory allocated"); +#endif + + memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); + vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; +#ifdef DEBUG + Serial.println(vga_stride); + Serial.println(vga_height); + Serial.println("Screen cleared"); +#endif + } + + return(GFX_OK); +} + +gfx_mode_t T4_DSP::getMode(void) +{ + return gfxmode; +} + +void T4_DSP::startRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + curTransfer = 0; + rstop = 0; + //dmatx.begin(true); + dmatx.attachInterrupt(TFT_isr); + setDmaStruct(); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + + digitalWrite(_cs, HIGH); + SPI.begin(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + + LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: + LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX + LPSPIP_TCR = 15; // Framesize 16 Bits + //LPSPIP_FCR = 0; // Fifo Watermark + LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable + LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: + dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); + + dmatx = dmasettings[0]; + digitalWrite(_cs, 0); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + dmatx.enable(); + } +} + + +void T4_DSP::stopRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + rstop = 1; + unsigned long m = millis(); + cancelled = true; + while (!rstop) { + if ((millis() - m) > 100) break; + delay(10); + asm volatile("wfi"); + }; + rstop = 0; + delay(50); + cancelled = false; + dmatx.detachInterrupt(); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + SPI.end(); +#ifdef ST7789 +// begin(gfxmode); +#endif + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + } +} + +int T4_DSP::get_frame_buffer_size(int *width, int *height) { + if (gfxmode < MODE_VGA_320x240) { + if (width != nullptr) *width = tft_width; + if (height != nullptr) *height = tft_height; + return tft_stride; + } + else { + if (width != nullptr) *width = vga_width; + if (height != nullptr) *height = vga_height; + return vga_stride; + } +} + +void T4_DSP::waitSync() +{ + if (gfxmode >= MODE_VGA_320x240) { + while (VSYNC == 0) {}; + } +} + +void T4_DSP::waitLine(int line) +{ + if (gfxmode >= MODE_VGA_320x240) { + while (currentLine != line) {}; + } +} + +/*********************************************************************************************** + No DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreenNoDma(uint16_t color) { + if (gfxmode < MODE_VGA_320x240) { + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + int i,j; + for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(arx, ary, arx+arw-1, ary+arh-1); + bitmap = bitmap + bmp_offy*w + bmp_offx; + for (int row=0;row> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + bits = *charpt++; + //digitalWrite(_dc, 1); + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + x +=8; + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + else { + drawText(x, y, text, fgcolor, bgcolor, doublesize); + } +} + + +/*********************************************************************************************** + DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreen(uint16_t color) { + int i,j; + if (gfxmode < MODE_VGA_320x240) { + for (j=0; j> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + dst=&tft_buffer[l*tft_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + x +=8; + } + } + else { + vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); + vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); + vga_pixel * dst; + while ((c = *text++)) { + const unsigned char * charpt=&font8x8[c][0]; + int l=y; + for (int i=0;i<8;i++) + { + unsigned char bits; + if (doublesize) { + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + x +=8; + } + } +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { + drawSprite(x,y,bitmap, 0,0,0,0); +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) +{ + int bmp_offx = 0; + int bmp_offy = 0; + uint16_t *bmp_ptr; + int w =*bitmap++; + int h = *bitmap++; + if ( (arw == 0) || (arh == 0) ) { + // no crop window + arx = x; + ary = y; + arw = w; + arh = h; + } + else { + if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + int l=ary; + bitmap = bitmap + bmp_offy*w + bmp_offx; + + if (gfxmode < MODE_VGA_320x240) { + for (int row=0;row tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]; + pos +=step; + } + #endif + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i 2) ) y += (tft_height-height)/2; + uint16_t * dst=&tft_buffer[y*tft_stride]; + if (width > tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]]; + pos +=step; + } +#endif + } + else if ((width*2) == tft_width) { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]]; + *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i tft_width) { + int step = ((width << 8)/tft_width); + int pos = 0; + for (int i=0; i> 8]]; + pos +=step; + } + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = pix; + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i +#include +#endif + +#include "platform_config.h" +#include "iopins.h" + + + +#ifndef TFT_WIDTH +#define TFT_WIDTH 320 +#endif +#define TFT_REALWIDTH 320 + +#ifndef TFT_HEIGHT +#define TFT_HEIGHT 240 +#endif +#define TFT_REALHEIGHT 240 + + +typedef enum gfx_mode_t +{ + MODE_UNDEFINED = 0, + MODE_TFTILI_320x240 = 1, + MODE_TFTST_320x240 = 2, + MODE_VGA_320x240 = 3, + MODE_VGA_320x480 = 4, + MODE_VGA_352x240 = 5, + MODE_VGA_352x480 = 6, + MODE_VGA_512x240 = 7, + MODE_VGA_512x480 = 8, + MODE_VGA_640x240 = 9, + MODE_VGA_640x480 = 10 +} gfx_mode_t; + +typedef enum gfx_error_t +{ + GFX_OK = 0, + GFX_ERROR = -1 +} gfx_error_t; + + +#ifdef __cplusplus + +class T4_DSP +{ + public: + T4_DSP(); + + gfx_error_t begin(gfx_mode_t mode); + gfx_mode_t getMode(void); + void startRefresh(void); + void stopRefresh(); + + int get_frame_buffer_size(int *width, int *height); + void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); + + // wait next Vsync + void waitSync(); + void waitLine(int line); + + // NoDMA functions + void fillScreenNoDma(uint16_t color); + void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + // DMA functions + void fillScreen(uint16_t color); + void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + void writeLine(int width, int height, int y, uint16_t *buf); + void writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + void writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16); + void writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + + protected: + static uint8_t _rst, _cs, _dc; + static uint8_t _mosi, _sclk; + static uint8_t _vsync_pin; + static DMAChannel flexio1DMA; + static DMAChannel flexio2DMA; + void tft_setup(bool isST); + static void TFT_isr(void); + static void QT3_isr(void); +}; + +#endif +#endif diff --git a/MCUME_teensy41/teensy81/teensy81.ino b/MCUME_teensy41/teensy81/teensy81.ino index 3bc141b..a0867e4 100644 --- a/MCUME_teensy41/teensy81/teensy81.ino +++ b/MCUME_teensy41/teensy81/teensy81.ino @@ -3,134 +3,21 @@ extern "C" { #include "emuapi.h" } -extern "C" { -#include "zx81.h" -} - -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -TFT_T_DMA tft; -#else -#include "tft_t_dma.h" -TFT_T_DMA tft = TFT_T_DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, TFT_TOUCH_CS, TFT_TOUCH_INT); -#endif - -bool vgaMode = false; - -static unsigned char palette8[PALETTE_SIZE]; -static unsigned short palette16[PALETTE_SIZE]; -static IntervalTimer myTimer; -volatile boolean vbl=true; -static int skip=0; -static elapsedMicros tius; - -static void vblCount() { - if (vbl) { - vbl = false; - } else { - vbl = true; - } -} - -void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) -{ - if (index>8, - 320 & 0xFF, // YEND = 320 - ST7735_INVON , DELAY, // 7: hack - 10, - ST7735_NORON , DELAY, // 8: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 9: Main screen turn on, no args, w/delay - 255 -#endif -}; - -static void dmaInterrupt() { - dmatx.clearInterrupt(); - curTransfer++; - if (curTransfer >= nbTransfer) { - curTransfer = 0; - if (cancelled) { - dmatx.disable(); - rstop = 1; - } - } - arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2); -} - -static void setDmaStruct() { - uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; - int i=0; - uint16_t col=RGBVAL16(0x00,0x00,0x00);; - while (remaining > 0) { - uint16_t * fb = blocks[i]; - int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining); -#ifdef TFT_DEBUG - Serial.println((unsigned long)blocks[i]); - Serial.println(remaining); -#endif - switch (i) { - case 0: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb0[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0x00); -#endif - break; - case 1: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb1[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0xff); -#endif - break; - case 2: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb2[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0x00,0xff); -#endif - break; - case 3: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb3[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0xff,0x00,0xff); -#endif - break; - } - blocks[i] = fb; - if (blocks[i] == 0) { - Serial.print("ILI9341 allocaltion failed for block "); - Serial.println(i); - delay(10000); - } - - for (int j=0;jATTR_DST = 1; - dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); - dmasettings[i].interruptAtCompletion(); - remaining -= len; - i++; - } - dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); - nbTransfer = i; -#ifdef TFT_DEBUG - Serial.println(nbTransfer); -#endif -} - - -TFT_T_DMA::TFT_T_DMA(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso, uint8_t touch_cs, uint8_t touch_irq) -{ - _cs = cs; - _dc = dc; - _rst = rst; - _mosi = mosi; - _sclk = sclk; - _miso = miso; - pinMode(_dc, OUTPUT); - pinMode(_cs, OUTPUT); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); - if ( (touch_cs != 255) && (touch_irq != 255) ) { - _touch_irq = touch_irq; - _touch_cs = touch_cs; - pinMode(_touch_cs, OUTPUT); - pinMode(touch_irq, INPUT_PULLUP); - digitalWrite(_touch_cs, 1); - } -} - - -void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { - int dx=0; - int dy=0; -#ifdef ST7789 - if (TFT_REALWIDTH == TFT_REALHEIGHT) - { -#ifdef ROTATE_SCREEN - if (!flipped) { - dy += 80; - } -#else - if (flipped) { - dx += 80; - } -#endif - } -#endif - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - SPI.transfer16(x1+dx); - digitalWrite(_dc, 1); - SPI.transfer16(x2+dx); - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - digitalWrite(_dc, 1); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - return; - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - - SPI.transfer16(x1+dx); - SPI.transfer16(x2+dx); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - -void TFT_T_DMA::begin(void) { - SPI.setMOSI(_mosi); - SPI.setMISO(_miso); - SPI.setSCK(_sclk); - SPI.begin(); - - // Initialize display - if (_rst != 0xff) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - const uint8_t *addr = init_commands; - digitalWrite(_cs, 0); -#ifdef ILI9341 - while (1) { - uint8_t count = *addr++; - if (count-- == 0) break; - - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - - while (count-- > 0) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - } - - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(ILI9341_DISPON); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); -#endif -#ifdef ST7789 - uint8_t numCommands, numArgs; - uint16_t ms; - numCommands = *addr++; // Number of commands to follow - while(numCommands--) { // For each command... - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - numArgs = *addr++; // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs > 1) { // For each argument... - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - numArgs--; - } - - if (numArgs) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - if(ms) { - ms = *addr++; // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - digitalWrite(_cs, 1); - SPI.endTransaction(); - delay(ms); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - } - } - digitalWrite(_cs, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - SPI.endTransaction(); - - cancelled = false; - -#ifdef FLIP_SCREEN - flipscreen(true); -#else - flipscreen(false); -#endif -#ifdef ST7789 - if (TFT_REALWIDTH != TFT_REALHEIGHT) - { - flipscreen(true); - } -#endif -}; - - - -void TFT_T_DMA::flipscreen(bool flip) -{ - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(TFT_MADCTL); - digitalWrite(_dc, 1); - if (flip) { - flipped=true; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB); -#endif -#endif - } - else { - flipped=false; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB); -#endif -#endif - } - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - -boolean TFT_T_DMA::isflipped(void) -{ - return(flipped); -} - - -#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) - - -void TFT_T_DMA::startDMA(void) { - curTransfer = 0; - rstop = 0; - //dmatx.begin(true); - dmatx.attachInterrupt(dmaInterrupt); - setDmaStruct(); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - - digitalWrite(_cs, HIGH); - SPI.begin(); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); - - - LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: - LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX - LPSPIP_TCR = 15; // Framesize 16 Bits - //LPSPIP_FCR = 0; // Fifo Watermark - LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable - LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: - dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); - - dmatx = dmasettings[0]; - digitalWrite(_cs, 0); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - dmatx.enable(); -} - - -void TFT_T_DMA::stopDMA(void) { - rstop = 0; - wait(); - delay(50); - cancelled = false; - dmatx.detachInterrupt(); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - SPI.end(); -#ifdef ST7789 - begin(); -#endif -#ifdef ILI9341 - SPI.begin(); - digitalWrite(_cs, 0); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - SPI.endTransaction(); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); -} - -void TFT_T_DMA::wait(void) { - rstop = 1; - unsigned long m = millis(); - cancelled = true; - while (!rstop) { - if ((millis() - m) > 100) break; - delay(10); - asm volatile("wfi"); - }; - rstop = 0; -} - -int TFT_T_DMA::get_frame_buffer_size(int *width, int *height){ - if (width != nullptr) *width = TFT_REALWIDTH; - if (height != nullptr) *height = TFT_REALHEIGHT; - return TFT_REALWIDTH; -} - - -/*********************************************************************************************** - Touch functions - ***********************************************************************************************/ -/* Code based on ... - * - * @file XPT2046.cpp - * @date 19.02.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the XPT2046 driver for Arduino. - */ - -#define ADC_MAX 0x0fff - -void TFT_T_DMA::enableTouchIrq() -{ - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 }; - SPI.transfer((void*)&buf[0],3); - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); -} - -//Default callibration for non flipped -#define TX_MIN 30 -#define TY_MIN 20 -#define TX_MAX 300 -#define TY_MAX 220 - -//Default callibration for flipped -#define TFX_MIN 20 -#define TFY_MIN 25 -#define TFX_MAX 288 -#define TFY_MAX 221 - -static uint16_t txMin; -static uint16_t tyMin; -static uint16_t txMax; -static uint16_t tyMax; - - -void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { - if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) { - txMin = xMin; - tyMin = yMin; - txMax = xMax; - tyMax = yMax; - } - else { - if (flipped) { - txMin = TFX_MIN; - tyMin = TFY_MIN; - txMax = TFX_MAX; - tyMax = TFY_MAX; - } - else { - txMin = TX_MIN; - tyMin = TY_MIN; - txMax = TX_MAX; - tyMax = TY_MAX; - } - } -} - - -void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - if ( TOUCH_ENABLED() ) { - uint16_t x = 0; - uint16_t y = 0; - uint16_t z1 = 0; - uint16_t z2 = 0; - uint8_t i = 0; - int16_t xraw=0, yraw=0; - - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - - for(; i < 15; i++) { - // SPI requirer 32bit aliment - uint8_t buf[12] = { - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00 - }; - SPI.transfer(&buf[0], &buf[0], 12); - y += (buf[1] << 8 | buf[2])>>3; - x += (buf[4] << 8 | buf[5])>>3; - z1 += (buf[7] << 8 | buf[8])>>3; - z2 += (buf[10] << 8 | buf[11])>>3; - } - enableTouchIrq(); - - if(i == 0) { - *oX = 0; - *oY = 0; - *oZ = 0; - } - else { - x /= i; - y /= i; - z1 /= i; - z2 /= i; - } - - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); - int z = z1 + ADC_MAX - z2; - if (flipped) { - xraw = x; - yraw = y; - } else { - xraw = ADC_MAX - x; - yraw = ADC_MAX - y; - } - xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1); - yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1); - - *oX = xraw; - *oY = yraw; - *oZ = z; - } - else - { - *oX = 0; - *oY = 0; - *oZ = 0; - } -} - -void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - readRaw(oX,oY,oZ); - // callibrate ... - if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin); - if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin); - //Serial.print(*oX); - //Serial.print(" "); - //Serial.println(*oY); -} - - -/*********************************************************************************************** - No DMA functions - ***********************************************************************************************/ -void TFT_T_DMA::fillScreenNoDma(uint16_t color) { - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - int i,j; - for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(arx, ary, arx+arw-1, ary+arh-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - bits = *charpt++; - //digitalWrite(_dc, 1); - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - x +=8; -#ifdef ILI9341 - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); -#endif - digitalWrite(_cs, 1); - SPI.endTransaction(); - } - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - - - -/*********************************************************************************************** - DMA functions - ***********************************************************************************************/ -uint16_t * TFT_T_DMA::getLineBuffer(int j) -{ - uint16_t * block=blocks[j>>6]; - return(&block[(j&0x3F)*TFT_REALWIDTH]); -} - -void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) { - uint8_t *buffer=buf; - uint8_t *src; - - int i,j,y=0; - if (width*2 <= TFT_REALWIDTH) { - for (j=0; j>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH]; - for (i=0; i>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x]; - for (i=0; i>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - block=blocks[l>>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt++; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - x +=8; - } -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { - drawSprite(x,y,bitmap, 0,0,0,0); -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) -{ - int bmp_offx = 0; - int bmp_offy = 0; - uint16_t *bmp_ptr; - - int w =*bitmap++; - int h = *bitmap++; - - - if ( (arw == 0) || (arh == 0) ) { - // no crop window - arx = x; - ary = y; - arw = w; - arh = h; - } - else { - if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - int l=ary; - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx]; - bmp_ptr = (uint16_t*)bitmap; - for (int col=0;col -#include -#include -#endif - -#include "tft_t_dma_config.h" - -#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) -#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define R16(rgb) ((rgb>>8)&0xf8) -#define G16(rgb) ((rgb>>3)&0xfc) -#define B16(rgb) ((rgb<<3)&0xf8) - -#define PAL_COLOR_MASK 0xff - -#ifdef LOHRES -#define TFT_WIDTH 240 -#define TFT_REALWIDTH 240 -#else -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 -#endif -#define TFT_HEIGHT 192 -#define TFT_REALHEIGHT 240 - -//#define WIDTH 272 -//#define HEIGHT 228 - -#define LINES_PER_BLOCK 64 -#define NR_OF_BLOCK 4 -#define SCREEN_DMA_NUM_SETTINGS NR_OF_BLOCK - - -#ifdef ILI9341 - -#define ILI9341_NOP 0x00 -#define ILI9341_SWRESET 0x01 -#define ILI9341_RDDID 0x04 -#define ILI9341_RDDST 0x09 - -#define ILI9341_SLPIN 0x10 -#define ILI9341_SLPOUT 0x11 -#define ILI9341_PTLON 0x12 -#define ILI9341_NORON 0x13 - -#define ILI9341_RDMODE 0x0A -#define ILI9341_RDMADCTL 0x0B -#define ILI9341_RDPIXFMT 0x0C -#define ILI9341_RDIMGFMT 0x0D -#define ILI9341_RDSELFDIAG 0x0F - -#define ILI9341_INVOFF 0x20 -#define ILI9341_INVON 0x21 -#define ILI9341_GAMMASET 0x26 -#define ILI9341_DISPOFF 0x28 -#define ILI9341_DISPON 0x29 - -#define ILI9341_CASET 0x2A -#define ILI9341_PASET 0x2B -#define ILI9341_RAMWR 0x2C -#define ILI9341_RAMRD 0x2E - -#define ILI9341_PTLAR 0x30 -#define ILI9341_MADCTL 0x36 -#define ILI9341_VSCRSADD 0x37 -#define ILI9341_PIXFMT 0x3A - -#define ILI9341_FRMCTR1 0xB1 -#define ILI9341_FRMCTR2 0xB2 -#define ILI9341_FRMCTR3 0xB3 -#define ILI9341_INVCTR 0xB4 -#define ILI9341_DFUNCTR 0xB6 - -#define ILI9341_PWCTR1 0xC0 -#define ILI9341_PWCTR2 0xC1 -#define ILI9341_PWCTR3 0xC2 -#define ILI9341_PWCTR4 0xC3 -#define ILI9341_PWCTR5 0xC4 -#define ILI9341_VMCTR1 0xC5 -#define ILI9341_VMCTR2 0xC7 - -#define ILI9341_RDID1 0xDA -#define ILI9341_RDID2 0xDB -#define ILI9341_RDID3 0xDC -#define ILI9341_RDID4 0xDD - -#define ILI9341_GMCTRP1 0xE0 -#define ILI9341_GMCTRN1 0xE1 - -#define ILI9341_MADCTL_MY 0x80 -#define ILI9341_MADCTL_MX 0x40 -#define ILI9341_MADCTL_MV 0x20 -#define ILI9341_MADCTL_ML 0x10 -#define ILI9341_MADCTL_RGB 0x00 -#define ILI9341_MADCTL_BGR 0x08 -#define ILI9341_MADCTL_MH 0x04 - -#define TFT_CASET ILI9341_CASET -#define TFT_PASET ILI9341_PASET -#define TFT_RAMWR ILI9341_RAMWR -#define TFT_MADCTL ILI9341_MADCTL - -#endif - - -#ifdef ST7789 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_RGB 0x00 -#define ST77XX_MADCTL_BGR 0x08 -#define ST77XX_MADCTL_MH 0x04 - -#define TFT_CASET ST7735_CASET -#define TFT_PASET ST7735_RASET -#define TFT_RAMWR ST7735_RAMWR -#define TFT_MADCTL ST7735_MADCTL - -#endif - - - -#ifdef __cplusplus - -class TFT_T_DMA -{ - public: - TFT_T_DMA(uint8_t _CS, uint8_t _DC, uint8_t _RST = 255, uint8_t _MOSI=11, uint8_t _SCLK=13, uint8_t _MISO=12, uint8_t touch_cs=38, uint8_t touch_irq=37); - - void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); - void begin(void); - void flipscreen(bool flip); - boolean isflipped(void); - void startDMA(void); - void stopDMA(); - int get_frame_buffer_size(int *width, int *height); - - // Touch screen functions - #define TOUCH_ENABLED() ((_touch_cs != 255) && (_touch_irq != 255)) - bool isTouching(void) { return ((!TOUCH_ENABLED())?false:(digitalRead(_touch_irq) == LOW)); } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax); - - // NoDMA functions - void writeScreenNoDma(const uint16_t *pcolors); - void fillScreenNoDma(uint16_t color); - void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - // DMA functions - uint16_t * getLineBuffer(int j); - void writeScreen(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int y, uint16_t *buf); - void fillScreen(uint16_t color); - void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - protected: - uint8_t _rst, _cs, _dc; - uint8_t _miso, _mosi, _sclk; - uint8_t _touch_irq=255, _touch_cs=255; - bool flipped=false; - - void wait(void); - void enableTouchIrq(); -}; - -#endif -#endif diff --git a/MCUME_teensy41/teensy81/tft_t_dma_config.h b/MCUME_teensy41/teensy81/tft_t_dma_config.h deleted file mode 100644 index 0a712da..0000000 --- a/MCUME_teensy41/teensy81/tft_t_dma_config.h +++ /dev/null @@ -1,13 +0,0 @@ -#include "platform_config.h" - -//#define ST7789 1 -//#define ILI9341 1 - -#define TFT_LINEARINT 1 -#define LINEARINT_HACK 1 - -//#define FLIP_SCREEN 1 -//#define TFT_DEBUG 1 -#if defined(__IMXRT1052__) || defined(__IMXRT1062__) -//#define TFT_STATICFB 1 -#endif diff --git a/MCUME_teensy41/teensy81/vga_t_dma.h b/MCUME_teensy41/teensy81/vga_t_dma.h deleted file mode 100644 index 81a986b..0000000 --- a/MCUME_teensy41/teensy81/vga_t_dma.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - Wrapping class to extend VGA_T4 to TFT_T_DMA -*/ - -#ifndef _VGA_T_DMAH_ -#define _VGA_T_DMAH_ - -#ifdef __cplusplus -#include -#endif - - -#define RGBVAL16(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) - - - - -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 - -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - - - -#ifdef __cplusplus - -class TFT_T_DMA: public VGA_T4 -{ - public: - // Fake touch screen functions - bool isTouching(void) { return false; } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { } - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { }; - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { } - - // fake DMA functions - void startDMA(void) { }; - void stopDMA(void) { }; - - // fake no DMA functions - void writeScreenNoDma(const vga_pixel *pcolors) { writeScreen(pcolors); } - void fillScreenNoDma(vga_pixel color) { clear(color); } - void drawTextNoDma(int16_t x, int16_t y, const char * text, vga_pixel fgcolor, vga_pixel bgcolor, bool doublesize) { drawText(x,y,text,fgcolor,bgcolor,doublesize); } - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, vga_pixel color) { drawRect(x, y, w, h, color); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap) { drawSprite(x, y, bitmap); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh) { drawSprite(x, y, bitmap, croparx, cropary, croparw, croparh); } -}; - - -#endif -#endif diff --git a/MCUME_teensy41/teensy81/zx81.c b/MCUME_teensy41/teensy81/wrapemu.c similarity index 99% rename from MCUME_teensy41/teensy81/zx81.c rename to MCUME_teensy41/teensy81/wrapemu.c index 82fc2d1..fa787b5 100644 --- a/MCUME_teensy41/teensy81/zx81.c +++ b/MCUME_teensy41/teensy81/wrapemu.c @@ -28,7 +28,7 @@ int zx80=0; int autoload=1; -struct { unsigned char R,G,B; } Palette[16] = { +struct { unsigned char R,G,B; } Palette[2] = { { 0, 0, 0}, { 255, 255, 255} }; @@ -225,7 +225,7 @@ emu_DrawVsync(); d <<= 1; } } - emu_DrawLine(&XBuf[0], WIDTH, HEIGHT, y); + emu_DrawLinePal16(&XBuf[0], WIDTH, HEIGHT, y); buf += (ZX_VID_FULLWIDTH/8); } } diff --git a/MCUME_teensy41/teensy81/zx81.h b/MCUME_teensy41/teensy81/wrapemu.h similarity index 100% rename from MCUME_teensy41/teensy81/zx81.h rename to MCUME_teensy41/teensy81/wrapemu.h diff --git a/MCUME_teensy41/teensyaiie/emuapi.cpp b/MCUME_teensy41/teensyaiie/emuapi.cpp index c367cb0..e128cca 100644 --- a/MCUME_teensy41/teensyaiie/emuapi.cpp +++ b/MCUME_teensy41/teensyaiie/emuapi.cpp @@ -5,25 +5,31 @@ extern "C" { #include "iopins.h" } -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#else -#include "tft_t_dma.h" -#endif +#include -#ifdef HAS_USBKEY +#ifdef HAS_USB #include "USBHost_t36.h" // Read this header first for key info USBHost myusb; USBHub hub1(myusb); +#ifdef HAS_USBKEY KeyboardController keyboard1(myusb); USBHIDParser hid1(myusb); MouseController mouse1(myusb); +#endif +#ifdef HAS_USBMIDI MIDIDevice midi1(myusb); #endif +#ifdef HAS_USBJOY +#define COUNT_JOYSTICKS 4 +JoystickController joysticks[COUNT_JOYSTICKS](myusb); +#endif +#endif static bool emu_writeConfig(void); static bool emu_readConfig(void); static bool emu_eraseConfig(void); +static bool emu_writeGfxConfig(char * display_type); +static int emu_readGfxConfig(void); static bool mouseDetected = false; static bool keyboardDetected = false; @@ -34,12 +40,13 @@ static File file; #define MAX_FILES 64 #define AUTORUN_FILENAME "autorun.txt" +#define GFX_CFG_FILENAME "gfxmode.txt" -#define MAX_FILENAME_SIZE 24 +#define MAX_FILENAME_SIZE 34 #define MAX_MENULINES 9 #define TEXT_HEIGHT 16 #define TEXT_WIDTH 8 -#define MENU_FILE_XOFFSET (6*TEXT_WIDTH) +#define MENU_FILE_XOFFSET (2*TEXT_WIDTH) #define MENU_FILE_YOFFSET (2*TEXT_HEIGHT) #define MENU_FILE_W (MAX_FILENAME_SIZE*TEXT_WIDTH) #define MENU_FILE_H (MAX_MENULINES*TEXT_HEIGHT) @@ -53,7 +60,8 @@ static File file; #define MENU_VGA_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) #define MENU_VGA_YOFFSET (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37) -extern TFT_T_DMA tft; +#include "t4_dsp.h" +T4_DSP tft; static int nbFiles=0; static int curFile=0; @@ -65,6 +73,8 @@ static char selected_filename[MAX_FILENAME_SIZE]=""; static char second_selected_filename[MAX_FILENAME_SIZE]=""; static bool menuRedraw=true; static bool autorun=false; +static bool vgahires=false; + static const unsigned short * keys; #ifdef TEECOMPUTER @@ -158,6 +168,29 @@ void emu_Free(void * pt) free(pt); } +#define SMEMPOOL (0x800000) +EXTMEM static unsigned char slowmem[SMEMPOOL]; +static int slowmempt = 0; + +void * emu_SMalloc(unsigned int size) +{ + void * mem = (void*)&slowmem[slowmempt]; + slowmempt += size; + + if ( slowmempt > SMEMPOOL ) { + mem = NULL; + emu_printf("failure to allocate slow"); + } + else { + emu_printf("could allocate slow static "); + emu_printf(size); + } + return mem; +} + +void emu_SFree(void * pt) +{ +} /******************************** * Input and keyboard ********************************/ @@ -329,6 +362,12 @@ int emu_ReadKeys(void) #endif if ( row & 0x02 ) retval |= MASK_JOY2_BTN; + +#ifdef EXTPAD + if ( sh_pressed ) retval |= MASK_KEY_USER3; + if ( fn_pressed ) retval |= MASK_KEY_USER1; + digitalWrite(KLED, 0); +#else // Handle LED flash uint32_t time_ms=millis(); if ((time_ms-last_t_ms) > 100) { @@ -412,8 +451,9 @@ int emu_ReadKeys(void) if ( key_fn ) retval |= MASK_KEY_USER2; if ( ( key_fn ) && (keymatrix[4] == 0x10 )) retval |= MASK_KEY_USER1; +#endif - if ( (key_fn) && (key_sh) ) + if ( (fn_pressed) && (sh_pressed) ) #else if ( ((retval & (MASK_KEY_USER1+MASK_KEY_USER2)) == (MASK_KEY_USER1+MASK_KEY_USER2)) || (retval & MASK_KEY_USER4 ) ) @@ -453,8 +493,10 @@ int emu_ReadKeys(void) while (true) { ; } -#endif +#endif } + + emu_GetJoystick(); return (retval); } @@ -607,7 +649,7 @@ int emu_setKeymap(int index) { } int emu_GetMouse(int *x, int *y, int *buts) { -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBKEY) if (mouse1.available()) { *buts = mouse1.getButtons(); *x = mouse1.getMouseX(); @@ -620,7 +662,23 @@ int emu_GetMouse(int *x, int *y, int *buts) { return 0; } -#ifdef HAS_USBKEY +int emu_GetJoystick(void) { +#if defined(HAS_USB) && (HAS_USBJOY) + for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) { + if (joysticks[joystick_index].available()) { + uint64_t axis_mask = joysticks[joystick_index].axisMask(); + uint64_t axis_changed_mask = joysticks[joystick_index].axisChangedMask(); + uint32_t buttons = joysticks[joystick_index].getButtons(); + Serial.printf("Joystick(%d): buttons = %x", joystick_index, buttons); + Serial.println(); + } + } + return 1; +#endif + return 0; +} + +#if defined(HAS_USB) && (HAS_USBKEY) void OnPress(auto key) { keyboardDetected = true; @@ -764,7 +822,7 @@ int emu_KeyboardDetected(void) { return (keyboardDetected?1:0); } -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) static unsigned char midiBuffer[16]; static unsigned char midiLastCmd=0; static int midiDataCnt=0; @@ -772,8 +830,7 @@ static int midiCmdNbParam=0; #endif void emu_MidiOnDataReceived(unsigned char value) { - -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) //Serial.println(value, HEX); //10000000 = 128 = note off //10010000 = 144 = note on @@ -941,6 +998,7 @@ void emu_MidiOnDataReceived(unsigned char value) { /******************************** * Menu file loader UI ********************************/ +#ifdef FILEBROWSER static int readNbFiles(void) { int totalFiles = 0; @@ -970,8 +1028,6 @@ static int readNbFiles(void) { return totalFiles; } - - void backgroundMenu(void) { menuRedraw=true; tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00)); @@ -981,11 +1037,13 @@ void backgroundMenu(void) { int handleMenu(uint16_t bClick) { if (autorun) { + toggleMenu(false); + menuRedraw=false; return (ACTION_RUN1); } int action = ACTION_NONE; - if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) ) { + if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) || ( bClick & MASK_KEY_USER2 ) ) { char newpath[MAX_FILENAME_PATH]; strcpy(newpath, selection); strcat(newpath, "/"); @@ -996,17 +1054,31 @@ int handleMenu(uint16_t bClick) File file = SD.open(selection); if (file.isDirectory()) { curFile = 0; - nbFiles = readNbFiles(); + nbFiles = readNbFiles(); + menuRedraw=true; } - else { - action = ACTION_RUN1; + else + { #ifdef TEECOMPUTER - if (key_extmode) { + if ( (key_extmode) || ( key_sh) ) { emu_writeConfig(); } + if ( tft.getMode() < MODE_VGA_320x240) { + if ( bClick & MASK_KEY_USER2 ) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + } + //emu_SwapJoysticks(0); #endif + toggleMenu(false); + menuRedraw=false; + return (ACTION_RUN1); } - menuRedraw=true; } else if ( bClick & MASK_KEY_USER1 ) { menuRedraw=true; @@ -1015,19 +1087,14 @@ int handleMenu(uint16_t bClick) strcat(second_selection, "/"); strcat(second_selection, second_selected_filename); action = ACTION_RUN2; - } - else if ( bClick & MASK_KEY_USER2 ) { - menuRedraw=true; - //action = ACTION_RUN3; - emu_SwapJoysticks(0); - } + } else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) { if (curFile!=0) { menuRedraw=true; curFile--; } } - else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { + else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { if ((curFile-9)>=0) { menuRedraw=true; curFile -= 9; @@ -1042,7 +1109,7 @@ int handleMenu(uint16_t bClick) menuRedraw=true; } } - else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { + else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { if ((curFile<(nbFiles-9)) && (nbFiles)) { curFile += 9; menuRedraw=true; @@ -1099,12 +1166,12 @@ int handleMenu(uint16_t bClick) return (action); } -bool menuActive(void) +int menuActive(void) { - return (menuOn); + return (menuOn?1:0); } -void toggleMenu(bool on) { +void toggleMenu(int on) { if (on) { menuOn=true; backgroundMenu(); @@ -1122,7 +1189,7 @@ char * menuSecondSelection(void) { return (second_selection); } - +#endif /******************************** * OSKB handling @@ -1140,8 +1207,9 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) char c[4] = {' ',0,' ',0}; const char * cpt = str; int i=0; - int fb_width,fb_height; - tft.get_frame_buffer_size(&fb_width, &fb_height); + int fb_width,fb_height,fbstride; + + fbstride = tft.get_frame_buffer_size(&fb_width, &fb_height); int ypos = (bottom?(fb_height-2*8):0); int line = row + (bottom?2:0); while ((c[1] = *cpt++)) @@ -1150,7 +1218,7 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0); else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff); if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff); - tft.drawTextNoDma(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); + tft.drawText(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); i++; } } @@ -1248,7 +1316,7 @@ int handleOSKB(void) { return retval; } -void toggleOSKB(bool forceon) { +void toggleOSKB(int forceon) { if (forceon) { oskbOn = true; drawOSKB(); @@ -1332,6 +1400,17 @@ int emu_FileRead(void * buf, int size, int handler) #endif } +int emu_FileWrite(void * buf, int size, int handler) +{ +// emu_printf("emu_FileWrite"); +// emu_printi(handler); +#ifdef HCFH + return (file.write(buf, size)); +#else + return (getFileHandler(handler).write(buf, size)); +#endif +} + int emu_FileGetc(int handler) { // emu_printf("FileGetc"); // emu_printi(handler); @@ -1404,6 +1483,9 @@ unsigned int emu_FileSize(const char * filepath) emu_printf(filesize); lofile.close(); } + else { + emu_printf("filesize failed"); + } return(filesize); } @@ -1489,6 +1571,48 @@ static bool emu_eraseConfig(void) SD.remove (ROMSDIR "/" AUTORUN_FILENAME); } +static bool emu_writeGfxConfig(char * display_type) +{ + bool retval = false; + SD.remove ("/" GFX_CFG_FILENAME); + if (strcmp(display_type, "VGA")) { + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(display_type, strlen(display_type)) != strlen(display_type)) { + emu_printf("GFX config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + } + return retval; +} + +#define CFG_VGA 0 +#define CFG_ILI 1 +#define CFG_ST 2 + +static int emu_readGfxConfig(void) +{ + int retval = CFG_VGA; // No file = VGA + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + if (filesize == 2) // "ST" + { + retval = CFG_ST; + } + else if (filesize == 3) // "ILI" + { + retval = CFG_ILI; + } + lofile.close(); + } + return retval; +} + /******************************** * File IO compatibility ********************************/ @@ -1670,62 +1794,249 @@ FRESULT f_mkdir (const char* path) /******************************** - * Initialization + * GFX wrapper ********************************/ -void emu_init(void) +static unsigned short palette16[PALETTE_SIZE]; +static IntervalTimer myTimer; +volatile boolean vbl=true; +volatile boolean vgatimervsync=false; +static void (*vblCallback)(void) = nullptr; +static int skip=0; + +static void vblCount() { + if (vbl) { + vbl = false; + } else { + vbl = true; + } +} + +void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) +{ + if (index= MODE_VGA_320x240 ) { + if (vgatimervsync) { + while (vbl==vb) {}; + } + else { + tft.waitSync(); + } + } + else { + while (vbl==vb) {}; + } + if (vblCallback != nullptr) { + vblCallback(); + } +} + +void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride) +{ + if (skip == 0) { + tft.writeScreenPal(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); + } +} +void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLinePal(width,height,line, VBuf, palette16); + } +} + +void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine(width,height,line, VBuf); + } +} + +void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine8(width,height,line, VBuf, palette16); + } +} + +int emu_IsVga(void) +{ + return (tft.getMode() >= MODE_VGA_320x240?1:0); +} + +int emu_IsVgaHires(void) +{ + return (tft.getMode() >= MODE_VGA_640x240?1:0); +} + +int emu_FrameSkip(void) +{ + return skip; +} + + +/******************************** + * AUDIO wrapper +********************************/ +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +AudioPlaySystem mymixer; + +void emu_sndInit() { + Serial.println("sound init"); + mymixer.begin_audio(256, mymixer.snd_Mixer); + mymixer.start(); +} + +void emu_sndPlaySound(int chan, int volume, int freq) +{ + if (chan < 6) { + mymixer.sound(chan, freq, volume); + } + /* + Serial.print(chan); + Serial.print(":" ); + Serial.print(volume); + Serial.print(":" ); + Serial.println(freq); + */ +} + +void emu_sndPlayBuzz(int size, int val) { + mymixer.buzz(size,val); + //Serial.print((val==1)?1:0); + //Serial.print(":"); + //Serial.println(size); +} +#endif + +/******************************** + * Initialization +********************************/ +void emu_init(int hires) { Serial.begin(115200); + vgahires = hires; -#ifdef HAS_USBKEY +#ifdef HAS_USB myusb.begin(); +#ifdef HAS_USBKEY keyboard1.attachPress(OnPress); keyboard1.attachRelease(OnRelease); #endif +#endif - while (!SD.begin(SD_CS)) +#ifdef FILEBROWSER + if (!SD.begin(SD_CS)) { - Serial.println("SD begin failed, retrying..."); - delay(1000); + Serial.println("No SD card detected"); } strcpy(selection,ROMSDIR); - FileHandlersInit(); - nbFiles = readNbFiles(); - - Serial.print("SD initialized, files found: "); Serial.println(nbFiles); +#endif emu_InitJoysticks(); #ifdef SWAP_JOYSTICK - joySwapped = true; + joySwapped = true; #else - joySwapped = false; + joySwapped = false; #endif -#ifdef TEECOMPUTER -#ifndef HAS_T4_VGA - tft.flipscreen(false); -#endif -#endif int keypressed = emu_ReadKeys(); +#ifdef HAS_T4_VGA + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } +#else + int gfx_mode = CFG_VGA; // default +#ifdef FILEBROWSER + gfx_mode = emu_readGfxConfig(); +#endif + // Force VGA if UP pressed + if (keypressed & MASK_JOY2_UP) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("VGA"); +#endif + gfx_mode = CFG_VGA; + } + else { + if (keypressed & MASK_JOY2_LEFT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ST"); +#endif + gfx_mode = CFG_ST; + } + else if (keypressed & MASK_JOY2_RIGHT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ILI"); +#endif + gfx_mode = CFG_ILI; + } + } + if (gfx_mode == CFG_VGA) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + else + { + tft.begin(gfx_mode == CFG_ILI?MODE_TFTILI_320x240:MODE_TFTST_320x240); + } +#endif + if (keypressed & MASK_JOY2_DOWN) { tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) ); tft.drawTextNoDma(64,48, (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); +#ifdef FILEBROWSER emu_eraseConfig(); delay(1000); +#endif } else { +#ifdef FILEBROWSER if (emu_readConfig()) { autorun = true; } +#endif } +#ifdef FILEBROWSER toggleMenu(true); +#endif } -void emu_start(void) +void emu_start(int vblms, void * callback, int forcetimervsync) { + vgatimervsync = forcetimervsync?true:false; + tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); + tft.startRefresh(); + if (callback != nullptr) { + vblCallback = callback; + } + + myTimer.begin(vblCount, vblms); +#ifdef HAS_SND + emu_sndInit(); +#endif usbnavpad = 0; } diff --git a/MCUME_teensy41/teensyaiie/emuapi.h b/MCUME_teensy41/teensyaiie/emuapi.h index aa38e61..5dd6130 100644 --- a/MCUME_teensy41/teensyaiie/emuapi.h +++ b/MCUME_teensy41/teensyaiie/emuapi.h @@ -2,126 +2,14 @@ #define EMUAPI_H #include "platform_config.h" - -#define CUSTOM_SND 1 -//#define TIMER_REND 1 - -#define EXTRA_HEAP 0x10 - -// Title: < > -#define TITLE " Apple2 Emulator " -#define ROMSDIR "apple2" - -#define emu_Init(ROM) { aiie_Init(); aiie_Start(ROM);} -#define emu_Step(x) { aiie_Step(); } -#define emu_Input(x) { aiie_Input(x); } - -#define MAX_FILENAME_PATH 64 -#define NB_FILE_HANDLER 4 -#define PALETTE_SIZE 256 -#define VID_FRAME_SKIP 0x0 -#define TFT_VBUFFER_YCROP 0 -#define SINGLELINE_RENDERING 1 - -#define R32(rgb) ((rgb>>16)&0xff) -#define G32(rgb) ((rgb>>8)&0xff) -#define B32(rgb) (rgb & 0xff) +#include "emucfg.h" #define ACTION_NONE 0 -#define ACTION_MAXKBDVAL 16 -#define ACTION_EXITKBD 128 -#define ACTION_RUN1 129 -#define ACTION_RUN2 130 -#define ACTION_RUN3 131 - - -#ifdef KEYMAP_PRESENT - -#define keylables_map0_0 (char *)"qwertyuiop\x1a" -#define keylables_map0_1 (char *)" asdfghjkl\x19" -#define keylables_map0_2 (char *)" zxcvbnm,.;/" -#define keylables_map0_3 (char *)" +\x10-" -const unsigned short key_map0[] = { - 'q','w','e','r','t','y','u','i','o','p',127, //lowecase - 0,'a','s','d','f','g','h','j','k','l',10, - 0,'z','x','c','v','b','n','m',',','.',';','/', - 0,0,0,0, //U L R D - 0,'+',' ','-' - }; - -#define keylables_map1_0 (char *)"1234567890 " -#define keylables_map1_1 (char *)" " -#define keylables_map1_2 (char *)" " -#define keylables_map1_3 (char *)" " - -const unsigned short key_map1[] = { - '1','2','3','4','5','6','7','8','9','0',0, // digit keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map2_0 (char *)"!\"#$%^&*()@" -#define keylables_map2_1 (char *)" " -#define keylables_map2_2 (char *)" <>:?" -#define keylables_map2_3 (char *)" =\x10_" -const unsigned short key_map2[] = { - '!','"','#','$','%','^','&','*','(',')','@', // shiftothers - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,'<','>',':','?', - 153,151,150,152, //U L R D - 0,'=',' ','_' - }; - -#define keylables_map3_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " -#define keylables_map3_1 (char *)" " -#define keylables_map3_2 (char *)" " -#define keylables_map3_3 (char *)" " - -const unsigned short key_map3[] = { - 129,130,131,132,133,134,135,136,0,0,0, // function keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map4_0 (char *)"QWERTYUIOP@" -#define keylables_map4_1 (char *)" ASDFGHJKL\x19" -#define keylables_map4_2 (char *)" ZXCVBNM<>:?" -#define keylables_map4_3 (char *)" =\x10_" -const unsigned short key_map4[] = { - 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase - 0,'A','S','D','F','G','H','J','K','L',10, - 0,'Z','X','C','V','B','N','M','<','>',':','?', - 0,0,0,0, - 0,'=',' ','_' - }; - -#define keylables_map5_0 (char *)" " -#define keylables_map5_1 (char *)" " -#define keylables_map5_2 (char *)" " -#define keylables_map5_3 (char *)" " - -const unsigned short key_map5[] = { - 0,0,0,0,0,0,0,0,0,0,0, // extra keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 153,151,150,152, //U L R D - 0,0,' ',0 - }; - -const unsigned short matkeys[] = { - 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 - 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 - 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 - 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN - 0x510,0x010,0x110,0x310, // row 4 - }; - -#endif +#define ACTION_RUN1 1 +#define ACTION_RUN2 2 +#define FORCE_VGATIMERVSYNC 1 +#define SUPPORT_HIRES 1 #define MASK_JOY2_RIGHT 0x0001 #define MASK_JOY2_LEFT 0x0002 @@ -138,22 +26,25 @@ const unsigned short matkeys[] = { #define MASK_JOY1_BTN 0x1000 #define MASK_KEY_USER4 0x2000 +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) #ifdef __cplusplus extern "C" { +extern void emu_init(int hires=0); +extern void emu_start(int vblms, void * callback, int forcetimervsync=0); #endif - -extern void emu_init(void); -extern void emu_start(void); extern void emu_printf(const char * text); extern void emu_printi(int val); extern void emu_printh(int val); extern void * emu_Malloc(unsigned int size); extern void * emu_MallocI(unsigned int size); extern void emu_Free(void * pt); +extern void * emu_SMalloc(unsigned int size); +extern void emu_SFree(void * pt); extern int emu_FileOpen(const char * filepath, const char * mode); extern int emu_FileRead(void * buf, int size, int handler); +extern int emu_FileWrite(void * buf, int size, int handler); extern int emu_FileGetc(int handler); extern int emu_FileSeek(int handler, int seek, int origin); extern int emu_FileTell(int handler); @@ -164,24 +55,23 @@ extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size); extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek); extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index); -extern void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride); -extern void emu_DrawLine(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line); extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line); +extern void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride); extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line); -extern void emu_CopyLine(int width, int height, int ysrc, int ydst); extern void emu_DrawVsync(void); extern int emu_FrameSkip(void); -extern void * emu_LineBuffer(int line); -extern void emu_tweakVideo(int shiftdelta, int numdelta, int denomdelta); +extern int emu_IsVga(void); +extern int emu_IsVgaHires(void); -extern bool menuActive(void); +extern int menuActive(void); extern char * menuSelection(void); extern char * menuSecondSelection(void); -extern void toggleMenu(bool on); +extern void toggleMenu(int on); extern int handleMenu(unsigned short bClick); extern int handleOSKB(void); -extern void toggleOSKB(bool forceon); +extern void toggleOSKB(int forceon); extern void emu_InitJoysticks(void); extern int emu_SwapJoysticks(int statusOnly); @@ -190,6 +80,7 @@ extern int emu_ReadKeys(void); extern int emu_GetPad(void); extern int emu_GetMouse(int *x, int *y, int *buts); extern int emu_MouseDetected(void); +extern int emu_GetJoystick(void); extern int emu_KeyboardDetected(void); extern int emu_ReadAnalogJoyX(int min, int max); extern int emu_ReadAnalogJoyY(int min, int max); diff --git a/MCUME_teensy41/teensyaiie/emucfg.h b/MCUME_teensy41/teensyaiie/emucfg.h new file mode 100644 index 0000000..f34ca52 --- /dev/null +++ b/MCUME_teensy41/teensyaiie/emucfg.h @@ -0,0 +1,115 @@ +#ifndef EMUCFG_H +#define EMUCFG_H + +#include "wrapemu.h" + +// Title: < > +#define TITLE " Apple2 Emulator " +#define ROMSDIR "apple2" + +#define emu_Init(ROM) { aiie_Init(); aiie_Start(ROM);} +#define emu_Step(x) { aiie_Step(); } +#define emu_Input(x) { aiie_Input(x); } + +#define MAX_FILENAME_PATH 64 +#define NB_FILE_HANDLER 4 + +#define PALETTE_SIZE 256 +#define VID_FRAME_SKIP 0x0 +#define TFT_VBUFFER_YCROP 0 +#define SINGLELINE_RENDERING 1 +#define CUSTOM_SND 1 +//#define TIMER_REND 1 +//#define EXTPAD 1 +#define EXTRA_HEAP 0x10 +#define FILEBROWSER 1 + + +#ifdef KEYMAP_PRESENT + +#define keylables_map0_0 (char *)"qwertyuiop\x1a" +#define keylables_map0_1 (char *)" asdfghjkl\x19" +#define keylables_map0_2 (char *)" zxcvbnm,.;/" +#define keylables_map0_3 (char *)" +\x10-" +const unsigned short key_map0[] = { + 'q','w','e','r','t','y','u','i','o','p',127, //lowecase + 0,'a','s','d','f','g','h','j','k','l',10, + 0,'z','x','c','v','b','n','m',',','.',';','/', + 0,0,0,0, //U L R D + 0,'+',' ','-' + }; + +#define keylables_map1_0 (char *)"1234567890 " +#define keylables_map1_1 (char *)" " +#define keylables_map1_2 (char *)" " +#define keylables_map1_3 (char *)" " + +const unsigned short key_map1[] = { + '1','2','3','4','5','6','7','8','9','0',0, // digit keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map2_0 (char *)"!\"#$%^&*()@" +#define keylables_map2_1 (char *)" " +#define keylables_map2_2 (char *)" <>:?" +#define keylables_map2_3 (char *)" =\x10_" +const unsigned short key_map2[] = { + '!','"','#','$','%','^','&','*','(',')','@', // shiftothers + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 153,151,150,152, //U L R D + 0,'=',' ','_' + }; + +#define keylables_map3_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " +#define keylables_map3_1 (char *)" " +#define keylables_map3_2 (char *)" " +#define keylables_map3_3 (char *)" " + +const unsigned short key_map3[] = { + 129,130,131,132,133,134,135,136,0,0,0, // function keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map4_0 (char *)"QWERTYUIOP@" +#define keylables_map4_1 (char *)" ASDFGHJKL\x19" +#define keylables_map4_2 (char *)" ZXCVBNM<>:?" +#define keylables_map4_3 (char *)" =\x10_" +const unsigned short key_map4[] = { + 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase + 0,'A','S','D','F','G','H','J','K','L',10, + 0,'Z','X','C','V','B','N','M','<','>',':','?', + 0,0,0,0, + 0,'=',' ','_' + }; + +#define keylables_map5_0 (char *)" " +#define keylables_map5_1 (char *)" " +#define keylables_map5_2 (char *)" " +#define keylables_map5_3 (char *)" " + +const unsigned short key_map5[] = { + 0,0,0,0,0,0,0,0,0,0,0, // extra keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 153,151,150,152, //U L R D + 0,0,' ',0 + }; + +const unsigned short matkeys[] = { + 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 + 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 + 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 + 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN + 0x510,0x010,0x110,0x310, // row 4 + }; + +#endif + +#endif diff --git a/MCUME_teensy41/teensyaiie/platform_config.h b/MCUME_teensy41/teensyaiie/platform_config.h index 7495d5a..1791885 100644 --- a/MCUME_teensy41/teensyaiie/platform_config.h +++ b/MCUME_teensy41/teensyaiie/platform_config.h @@ -4,13 +4,13 @@ #define TEECOMPUTER 1 #ifdef TEECOMPUTER -//#define ILI9341 1 -//#define ST7789 1 -//#define TFTSPI1 1 -#define HAS_T4_VGA 1 +#define TFTSPI1 1 +//#define HAS_T4_VGA 1 //#define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 -#define INVX 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 #define PT8211 1 #else @@ -18,8 +18,12 @@ #define HAS_T4_VGA 1 //#define INVX 1 #define INVY 1 -#define HAS_SND 1 +//#define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 +#define PT8211 1 #endif diff --git a/MCUME_teensy41/teensyaiie/plf-display.cpp b/MCUME_teensy41/teensyaiie/plf-display.cpp index f257f3a..3d09cc6 100644 --- a/MCUME_teensy41/teensyaiie/plf-display.cpp +++ b/MCUME_teensy41/teensyaiie/plf-display.cpp @@ -7,15 +7,8 @@ extern "C" { #include #include "bios-font.h" -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -typedef uint8_t Pixel; -#define RGBVAL(r,g,b) RGBVAL8(r,g,b) -#else -#include "tft_t_dma.h" typedef uint16_t Pixel; #define RGBVAL(r,g,b) RGBVAL16(r,g,b) -#endif #include "globals.h" #include "applevm.h" @@ -83,14 +76,15 @@ void PlfDisplay::redraw() { } - +static Pixel linebuffer[DISPLAYWIDTH]; + void PlfDisplay::blit(AiieRect r) { uint8_t *videoBuffer = g_vm->videoBuffer; // FIXME: poking deep uint16_t pixel; for (uint8_t y=r.top; y<=r.bottom; y++) { - Pixel * scrlinept = (Pixel *)emu_LineBuffer(y); - scrlinept += (TFT_WIDTH - (r.right - r.left))/2; + Pixel * scrlinept = &linebuffer[0]; // (Pixel *)emu_LineBuffer(y); + scrlinept += (DISPLAYWIDTH - (r.right - r.left))/2; for (uint16_t x=r.left; x<=r.right; x++) { pixel = y * (DISPLAYRUN >> 1) + (x >> 1); uint8_t colorIdx; @@ -101,6 +95,7 @@ void PlfDisplay::blit(AiieRect r) } scrlinept[x] = loresPixelColors[colorIdx]; } + emu_DrawLine16(&linebuffer[0], DISPLAYWIDTH, 200 /*DISPLAYHEIGHT*/, y); } } diff --git a/MCUME_teensy41/teensyaiie/t4_dsp.cpp b/MCUME_teensy41/teensyaiie/t4_dsp.cpp new file mode 100644 index 0000000..43301fa --- /dev/null +++ b/MCUME_teensy41/teensyaiie/t4_dsp.cpp @@ -0,0 +1,1774 @@ +/* + TFT/VGA driver + DMA TFT driver based on C64 ILI9341 dma driver from Frank Bösing, 2017 +*/ + +#include "T4_DSP.h" + +#include +#include + +#include "font8x8.h" + +// TFT constants and variables +#define TFT_LINEARINT 1 +#define LINEARINT_HACK 1 +#define DMA_LINES_PER_BLOCK 64 +#define DMA_NUM_SETTINGS 4 + +#define TFT_SWRESET 0x01 +#define TFT_SLPOUT 0x11 +#define TFT_INVON 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_MADCTL 0x36 +#define TFT_PIXFMT 0x3A +#define TFT_MADCTL_MY 0x80 +#define TFT_MADCTL_MX 0x40 +#define TFT_MADCTL_MV 0x20 +#define TFT_MADCTL_ML 0x10 +#define TFT_MADCTL_RGB 0x00 +#define TFT_MADCTL_BGR 0x08 +#define TFT_MADCTL_MH 0x04 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) +//#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) +//#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) +//#define R16(rgb) ((rgb>>8)&0xf8) +//#define G16(rgb) ((rgb>>3)&0xfc) +//#define B16(rgb) ((rgb<<3)&0xf8) + +// LPSPI4 = SPI0 in Teensy 4.0 +// LPSPI3 = SPI1 in Teensy 4.0 +// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) + +#ifdef TFTSPI1 +#define SPI SPI1 +#define LPSPIP_TDR LPSPI3_TDR +#define LPSPIP_CR LPSPI3_CR +#define LPSPIP_CFGR1 LPSPI3_CFGR1 +#define LPSPIP_TCR LPSPI3_TCR +#define LPSPIP_DER LPSPI3_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX +#else +#define LPSPIP_TDR LPSPI4_TDR +#define LPSPIP_CR LPSPI4_CR +#define LPSPIP_CFGR1 LPSPI4_CFGR1 +#define LPSPIP_TCR LPSPI4_TCR +#define LPSPIP_DER LPSPI4_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX +#endif + +#define SPICLOCK 60000000 +#define SPI_MODE SPI_MODE0 + +// VGA constants and macros +typedef uint8_t vga_pixel; +#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) + +static DMASetting dmasettings[DMA_NUM_SETTINGS]; +static DMAChannel dmatx; +static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K +static volatile uint8_t rstop = 0; +static volatile bool cancelled = false; +static volatile uint8_t curTransfer = 0; +static uint8_t nbTransfer = 0; +static uint16_t * tft_buffer; +static int tft_width; +static int tft_height; +static int tft_stride; + +#define DELAY_MASK 0x80 +PROGMEM static const uint8_t init_commands[] = { + 1+DELAY_MASK, TFT_SWRESET, 150, + 1+DELAY_MASK, TFT_SLPOUT, 255, + 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, + 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, + 1, TFT_INVON, + 1, TFT_DISPON, + 0 +}; + +// VGA constants and variables +// Objective: +// generates VGA signal fully in hardware with as little as possible CPU help + +// Principle: +// QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) +// 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate +// RGB out, combined to create 8bits(/12bits) output. + +// Note: +// - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels +// - experimental resolution: 352x240,352x480 +// - experimental resolution: 512x240,512x480 (not stable) +// - video memory is allocated using malloc in T4 heap +// - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing +// but tried to be compensated by pixel shifting +// - Default is 8bits RRRGGGBB (332) +// But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! +// - Only ok at 600MHz else some disturbances visible + + + +#define TOP_BORDER 40 +#define PIN_HBLANK 15 + +#define PIN_R_B2 33 +#define PIN_R_B1 4 +#define PIN_R_B0 3 +#define PIN_G_B2 2 +#define PIN_G_B1 13 +#define PIN_G_B0 11 +#define PIN_B_B1 12 +#define PIN_B_B0 10 + + +#define DMA_HACK 0x80 + +#define R16(rgb) ((rgb>>8)&0xf8) +#define G16(rgb) ((rgb>>3)&0xfc) +#define B16(rgb) ((rgb<<3)&0xf8) + +// VGA 640x480@60Hz +// Screen refresh rate 60 Hz +// Vertical refresh 31.46875 kHz +// Pixel freq. 25.175 MHz +// +// Visible area 640 25.422045680238 us +// Front porch 16 0.63555114200596 us +// Sync pulse 96 3.8133068520357 us +// Back porch 48 1.9066534260179 us +// Whole line 800 31.777557100298 us + +#define frame_freq 60.0 // Hz +#define line_freq 31.46875 // KHz +#define pix_freq (line_freq*800) // KHz (25.175 MHz) + +// pix_period = 39.7ns +// H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) +#define frontporch_pix 20 //16 +#define backporch_pix 44 //48 + +// Flexio Clock +// PLL3 SW CLOCK (3) => 480 MHz +// PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) +#define FLEXIO_CLK_SEL_PLL3 3 +#define FLEXIO_CLK_SEL_PLL5 2 + +/* Set video PLL */ +// There are /1, /2, /4, /8, /16 post dividers for the Video PLL. +// The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, +// and CCM_ANALOG_MISC2 register sets according to the following equation. +// PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + +// nfact: +// This field controls the PLL loop divider. +// Valid range for DIV_SELECT divider value: 27~54. + +#define POST_DIV_SELECT 2 + +// Full buffer including back/front porch +static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; +static uint32_t dstbuffer __attribute__((aligned(32))); + +// Visible vuffer +static vga_pixel * vga_buffer; +static int vga_width; +static int vga_height; +static int vga_stride; + +static int maxpixperline; +static int left_border; +static int right_border; +static int line_double; +static int pix_shift; +static int ref_div_select; +static int ref_freq_num; +static int ref_freq_denom; +static int ref_pix_shift; +static int combine_shiftreg; + +#ifdef DEBUG +static uint32_t ISRTicks_prev = 0; +volatile uint32_t ISRTicks = 0; +#endif + +uint8_t T4_DSP::_rst; +uint8_t T4_DSP::_cs; +uint8_t T4_DSP::_dc; +uint8_t T4_DSP::_mosi; +uint8_t T4_DSP::_sclk; +uint8_t T4_DSP::_vsync_pin = -1; +DMAChannel T4_DSP::flexio1DMA; +DMAChannel T4_DSP::flexio2DMA; + +static volatile uint32_t VSYNC = 0; +static volatile uint32_t currentLine=0; +#define NOP asm volatile("nop\n\t"); +static gfx_mode_t gfxmode = MODE_UNDEFINED; + + +FASTRUN void T4_DSP::TFT_isr(void) { + dmatx.clearInterrupt(); + curTransfer++; + if (curTransfer >= nbTransfer) { + curTransfer = 0; + if (cancelled) { + dmatx.disable(); + rstop = 1; + } + } + arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); +} + +FASTRUN void T4_DSP::QT3_isr(void) { + TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); + TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); + + cli(); + + // V-PULSE + if (currentLine > 0) { + digitalWrite(_vsync_pin, 1); + VSYNC = 0; + } else { + digitalWrite(_vsync_pin, 0); + VSYNC = 1; + } + + currentLine++; + currentLine = currentLine % 525; + + + uint32_t y = (currentLine - TOP_BORDER) >> line_double; + // Visible area + + if (y >= 0 && y < vga_height) { + // Disable DMAs + //DMA_CERQ = flexio2DMA.channel; + //DMA_CERQ = flexio1DMA.channel; + + // Setup source adress + // Aligned 32 bits copy + unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; + flexio2DMA.TCD->SADDR = p; + if (pix_shift & DMA_HACK) + { + // Unaligned copy + uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; + flexio1DMA.TCD->SADDR = p2; + } + else { + p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 + flexio1DMA.TCD->SADDR = p; + } + + // Enable DMAs + //flexio2DMA.enable(); + //flexio1DMA.enable(); + DMA_SERQ = flexio2DMA.channel; + DMA_SERQ = flexio1DMA.channel; + arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); + } + sei(); + +#ifdef DEBUG + ISRTicks++; +#endif + asm volatile("dsb"); +} + +static void setDmaStruct() { + uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; + uint16_t * fb = (uint16_t*)malloc(remaining); + tft_buffer = fb; + tft_width = TFT_WIDTH; + tft_height = TFT_HEIGHT; + tft_stride = TFT_WIDTH; + uint16_t col=RGBVAL16(0x00,0x00,0x00); + int i=0; + while (remaining > 0) { + int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); + blocks[i] = fb; + for (int j=0;jATTR_DST = 1; + dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); + dmasettings[i].interruptAtCompletion(); + fb += len/2; + remaining -= len; + i++; + } + dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); + nbTransfer = i; +} + +static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 +{ +//if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; + CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE + | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 + | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); + CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; + CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock + const int div_post_pll = 1; // other values: 2,4 + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass +} + +T4_DSP::T4_DSP() +{ + _cs = TFT_CS; + _dc = TFT_DC; + _rst = TFT_RST; + _mosi = TFT_MOSI; + _sclk = TFT_SCLK; + pinMode(_dc, OUTPUT); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, 1); + digitalWrite(_dc, 1); + _vsync_pin = 8; +} + + +void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { + int dx=0; + int dy=0; + digitalWrite(_dc, 0); + SPI.transfer(TFT_CASET); + digitalWrite(_dc, 1); + SPI.transfer16(x1+dx); + digitalWrite(_dc, 1); + SPI.transfer16(x2+dx); + digitalWrite(_dc, 0); + SPI.transfer(TFT_PASET); + digitalWrite(_dc, 1); + SPI.transfer16(y1+dy); + digitalWrite(_dc, 1); + SPI.transfer16(y2+dy); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + return; +} + +void T4_DSP::tft_setup(bool isST) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + // RESET if reset pin defined + if (_rst != 0xff) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + const uint8_t *addr = init_commands; + uint8_t count; + digitalWrite(_cs, 0); + while (count = *addr++) { + uint8_t command = *addr++; + if ( (command == TFT_INVON) && (!isST) ) { + // Skip TFT_INVON for ILI + } + else { + digitalWrite(_dc, 0); // command + SPI.transfer(command); + uint16_t ms = count & DELAY_MASK; + count &= ~DELAY_MASK; + while (--count > 0) { // data + uint8_t data = *addr++; + if ( (command == TFT_MADCTL) && (isST) ) { + data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; + } + digitalWrite(_dc, 1); + SPI.transfer(data); + } + if (ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + digitalWrite(_cs, 1); + SPI.endTransaction(); + delay(2); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + } + } + } + digitalWrite(_cs, 1); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + SPI.endTransaction(); + /* + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_dc, 0); + digitalWrite(_cs, 0); + SPI.transfer(TFT_MADCTL); + digitalWrite(_dc, 1); + SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); + // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); + digitalWrite(_cs, 1); + SPI.endTransaction(); + */ + cancelled = false; +} + +// display VGA image +gfx_error_t T4_DSP::begin(gfx_mode_t mode) +{ + uint32_t flexio_clock_div; + combine_shiftreg = 0; +// int div_select = 49; +// int num = 135; +// int denom = 100; + int div_select = 20; + int num = 9800; + int denom = 10000; + int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; + int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; + set_videoClock(div_select,num,denom,true); + +#ifdef DEBUG + Serial.println(mode); + Serial.println("mode"); +#endif + + switch(mode) + { + case MODE_TFTILI_320x240: +#ifdef DEBUG + Serial.println("TFTILI_320x240"); +#endif + tft_setup(false); + gfxmode = mode; + break; + case MODE_TFTST_320x240: +#ifdef DEBUG + Serial.println("TFTST_320x240"); +#endif + tft_setup(true); + gfxmode = mode; + break; + + case MODE_VGA_320x240: +#ifdef DEBUG + Serial.println("VGA_320x240"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_320x480: +#ifdef DEBUG + Serial.println("VGA_320x480"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_640x240: +#ifdef DEBUG + Serial.println("VGA_640x240"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/pix_freq; + line_double = 1; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_640x480: +#ifdef DEBUG + Serial.println("VGA_640x480"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = (flexio_freq/pix_freq); + line_double = 0; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_512x240: +#ifdef DEBUG + Serial.println("VGA_512x240"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 1; + pix_shift = 0; + break; + + case MODE_VGA_512x480: +#ifdef DEBUG + Serial.println("VGA_512x480"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 0; + pix_shift = 0; + break; + + case MODE_VGA_352x240: +#ifdef DEBUG + Serial.println("VGA_352x240"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_352x480: +#ifdef DEBUG + Serial.println("VGA_352x480"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + } + + if (mode >= MODE_VGA_320x240) + { + if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { + fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); + digitalWrite(_cs, 0); + digitalWrite(_dc, 0); + SPI.transfer(TFT_DISPOFF); + digitalWrite(_cs, 1); + delay(20); + digitalWrite(_cs, 0); + digitalWrite(_cs, 1); + } + gfxmode = mode; + + maxpixperline = vga_stride; + // Save param for tweek adjustment + ref_div_select = div_select; + ref_freq_num = num; + ref_freq_denom = denom; + ref_pix_shift = pix_shift; + +#ifdef DEBUG + Serial.println("frequency"); + Serial.println(flexio_freq); + Serial.println("div"); + Serial.println(flexio_freq/pix_freq); +#endif + + pinMode(_vsync_pin, OUTPUT); + pinMode(PIN_HBLANK, OUTPUT); + + /* Basic pin setup FlexIO1 */ + pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 + pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 + pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 + pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 + /* Basic pin setup FlexIO2 */ + pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 + pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 + pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 + pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 + + /* High speed and drive strength configuration */ + *(portControlRegister(PIN_G_B2)) = 0xFF; + *(portControlRegister(PIN_R_B0)) = 0xFF; + *(portControlRegister(PIN_R_B1)) = 0xFF; + *(portControlRegister(PIN_R_B2)) = 0xFF; + *(portControlRegister(PIN_B_B0)) = 0xFF; + *(portControlRegister(PIN_B_B1)) = 0xFF; + *(portControlRegister(PIN_G_B0)) = 0xFF; + *(portControlRegister(PIN_G_B1)) = 0xFF; + + /* Set clock for FlexIO1 and FlexIO2 */ + CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) + | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); + CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) + | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); + + + /* Set up pin mux FlexIO1 */ + *(portConfigRegister(PIN_G_B2)) = 0x14; + *(portConfigRegister(PIN_R_B0)) = 0x14; + *(portConfigRegister(PIN_R_B1)) = 0x14; + *(portConfigRegister(PIN_R_B2)) = 0x14; + /* Set up pin mux FlexIO2 */ + *(portConfigRegister(PIN_B_B0)) = 0x14; + *(portConfigRegister(PIN_B_B1)) = 0x14; + *(portConfigRegister(PIN_G_B0)) = 0x14; + *(portConfigRegister(PIN_G_B1)) = 0x14; + + /* Enable the clock */ + CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + /* Enable the FlexIO with fast access */ + FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + + uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; + uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; + + /* Shifter 0 registers for FlexIO2 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 + inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter + stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled + startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable + timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 + timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock + pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output + pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity + shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode + /* Shifter 0 registers for FlexIO1 */ + FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + /* Shifter 0 registers for FlexIO1 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 + FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + if (combine_shiftreg) { + pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled + FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + } + /* Timer 0 registers for FlexIO2 */ + timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset + timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output + timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset + timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare + timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert + stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled + startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled + if (combine_shiftreg) { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag + } + else { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag + } + triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low + triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected + pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled + //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 + //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high + timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode + // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) + + int shifts_per_transfer; + if (combine_shiftreg) { + shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 + } + else { + shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 + } + FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); + /* Timer 0 registers for FlexIO1 */ + FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); +#ifdef DEBUG + Serial.println("FlexIO setup complete"); +#endif + + /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ + if (combine_shiftreg) { + FLEXIO2_SHIFTSDEN |= (1<<1); + FLEXIO1_SHIFTSDEN |= (1<<1); + } + else { + FLEXIO2_SHIFTSDEN |= (1<<0); + FLEXIO1_SHIFTSDEN |= (1<<0); + } + /* Disable DMA channel so it doesn't start transferring yet */ + flexio1DMA.disable(); + flexio2DMA.disable(); + /* Set up DMA channel to use Shifter 0 trigger */ + flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); + flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); + + + if (combine_shiftreg) { + flexio2DMA.TCD->NBYTES = 8; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 8; + flexio2DMA.TCD->CITER = maxpixperline / 8; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + flexio1DMA.TCD->NBYTES = 8; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 8; + flexio1DMA.TCD->CITER = maxpixperline / 8; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Setup DMA2 Flexio2 copy + flexio2DMA.TCD->NBYTES = 4; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 4; + flexio2DMA.TCD->CITER = maxpixperline / 4; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + // Setup DMA1 Flexio1 copy + // Use pixel shift to avoid color smearing? + if (pix_shift & DMA_HACK) + { + if (pix_shift & 0x3 == 0) { + // Aligned 32 bits copy (32bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Unaligned (source) 32 bits copy (8bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 1; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion + } + } + else + { + // Aligned 32 bits copy + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + } + +#ifdef DEBUG + Serial.println("DMA setup complete"); +#endif + + // enable clocks for QTIMER3: generates the 15KHz for hsync + // Pulse: + // low : 3.8133 us => 569x6.7ns + // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) + // (OLD TEST) + // (4us low, 28us high => 32us) + // (597x6.7ns for 4us) + // (4179x6.7ns for 28us) + CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 + //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 + + #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz + #define MARGIN_D 1000 + + TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer + // Invert output pin as we want the interupt on rising edge + TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) + TMR3_CNTR3 = 0; + TMR3_LOAD3 = 0; + + /* Inverted timings */ + unsigned long long cpu_freq = F_CPU; + unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; + int rate2 = rate; + + int substract = 1; + if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { + substract=5; + rate2=1652; + } + + #ifdef DEBUG + Serial.print("MARGIN_N is: "); + Serial.println(rate2, DEC); + Serial.print("SUBSTRACT is: "); + Serial.println(substract, DEC); +#endif + TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; + TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; + /* + TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; + */ + TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on + TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), + // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) + //configure Teensy pin Compare output + IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 + attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function + NVIC_ENABLE_IRQ(IRQ_QTIMER3); +#ifdef DEBUG + Serial.println("QTIMER3 setup complete"); + Serial.print("V-PIN is "); + Serial.println(_vsync_pin); +#endif + + /* initialize gfx buffer */ + if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift + if (gfxbuffer == NULL) return(GFX_ERROR); +#ifdef DEBUG + Serial.println("Memory allocated"); +#endif + + memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); + vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; +#ifdef DEBUG + Serial.println(vga_stride); + Serial.println(vga_height); + Serial.println("Screen cleared"); +#endif + } + + return(GFX_OK); +} + +gfx_mode_t T4_DSP::getMode(void) +{ + return gfxmode; +} + +void T4_DSP::startRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + curTransfer = 0; + rstop = 0; + //dmatx.begin(true); + dmatx.attachInterrupt(TFT_isr); + setDmaStruct(); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + + digitalWrite(_cs, HIGH); + SPI.begin(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + + LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: + LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX + LPSPIP_TCR = 15; // Framesize 16 Bits + //LPSPIP_FCR = 0; // Fifo Watermark + LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable + LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: + dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); + + dmatx = dmasettings[0]; + digitalWrite(_cs, 0); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + dmatx.enable(); + } +} + + +void T4_DSP::stopRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + rstop = 1; + unsigned long m = millis(); + cancelled = true; + while (!rstop) { + if ((millis() - m) > 100) break; + delay(10); + asm volatile("wfi"); + }; + rstop = 0; + delay(50); + cancelled = false; + dmatx.detachInterrupt(); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + SPI.end(); +#ifdef ST7789 +// begin(gfxmode); +#endif + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + } +} + +int T4_DSP::get_frame_buffer_size(int *width, int *height) { + if (gfxmode < MODE_VGA_320x240) { + if (width != nullptr) *width = tft_width; + if (height != nullptr) *height = tft_height; + return tft_stride; + } + else { + if (width != nullptr) *width = vga_width; + if (height != nullptr) *height = vga_height; + return vga_stride; + } +} + +void T4_DSP::waitSync() +{ + if (gfxmode >= MODE_VGA_320x240) { + while (VSYNC == 0) {}; + } +} + +void T4_DSP::waitLine(int line) +{ + if (gfxmode >= MODE_VGA_320x240) { + while (currentLine != line) {}; + } +} + +/*********************************************************************************************** + No DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreenNoDma(uint16_t color) { + if (gfxmode < MODE_VGA_320x240) { + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + int i,j; + for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(arx, ary, arx+arw-1, ary+arh-1); + bitmap = bitmap + bmp_offy*w + bmp_offx; + for (int row=0;row> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + bits = *charpt++; + //digitalWrite(_dc, 1); + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + x +=8; + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + else { + drawText(x, y, text, fgcolor, bgcolor, doublesize); + } +} + + +/*********************************************************************************************** + DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreen(uint16_t color) { + int i,j; + if (gfxmode < MODE_VGA_320x240) { + for (j=0; j> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + dst=&tft_buffer[l*tft_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + x +=8; + } + } + else { + vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); + vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); + vga_pixel * dst; + while ((c = *text++)) { + const unsigned char * charpt=&font8x8[c][0]; + int l=y; + for (int i=0;i<8;i++) + { + unsigned char bits; + if (doublesize) { + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + x +=8; + } + } +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { + drawSprite(x,y,bitmap, 0,0,0,0); +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) +{ + int bmp_offx = 0; + int bmp_offy = 0; + uint16_t *bmp_ptr; + int w =*bitmap++; + int h = *bitmap++; + if ( (arw == 0) || (arh == 0) ) { + // no crop window + arx = x; + ary = y; + arw = w; + arh = h; + } + else { + if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + int l=ary; + bitmap = bitmap + bmp_offy*w + bmp_offx; + + if (gfxmode < MODE_VGA_320x240) { + for (int row=0;row tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]; + pos +=step; + } + #endif + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i 2) ) y += (tft_height-height)/2; + uint16_t * dst=&tft_buffer[y*tft_stride]; + if (width > tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]]; + pos +=step; + } +#endif + } + else if ((width*2) == tft_width) { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]]; + *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i tft_width) { + int step = ((width << 8)/tft_width); + int pos = 0; + for (int i=0; i> 8]]; + pos +=step; + } + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = pix; + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i +#include +#endif + +#include "platform_config.h" +#include "iopins.h" + + + +#ifndef TFT_WIDTH +#define TFT_WIDTH 320 +#endif +#define TFT_REALWIDTH 320 + +#ifndef TFT_HEIGHT +#define TFT_HEIGHT 240 +#endif +#define TFT_REALHEIGHT 240 + + +typedef enum gfx_mode_t +{ + MODE_UNDEFINED = 0, + MODE_TFTILI_320x240 = 1, + MODE_TFTST_320x240 = 2, + MODE_VGA_320x240 = 3, + MODE_VGA_320x480 = 4, + MODE_VGA_352x240 = 5, + MODE_VGA_352x480 = 6, + MODE_VGA_512x240 = 7, + MODE_VGA_512x480 = 8, + MODE_VGA_640x240 = 9, + MODE_VGA_640x480 = 10 +} gfx_mode_t; + +typedef enum gfx_error_t +{ + GFX_OK = 0, + GFX_ERROR = -1 +} gfx_error_t; + + +#ifdef __cplusplus + +class T4_DSP +{ + public: + T4_DSP(); + + gfx_error_t begin(gfx_mode_t mode); + gfx_mode_t getMode(void); + void startRefresh(void); + void stopRefresh(); + + int get_frame_buffer_size(int *width, int *height); + void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); + + // wait next Vsync + void waitSync(); + void waitLine(int line); + + // NoDMA functions + void fillScreenNoDma(uint16_t color); + void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + // DMA functions + void fillScreen(uint16_t color); + void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + void writeLine(int width, int height, int y, uint16_t *buf); + void writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + void writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16); + void writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + + protected: + static uint8_t _rst, _cs, _dc; + static uint8_t _mosi, _sclk; + static uint8_t _vsync_pin; + static DMAChannel flexio1DMA; + static DMAChannel flexio2DMA; + void tft_setup(bool isST); + static void TFT_isr(void); + static void QT3_isr(void); +}; + +#endif +#endif diff --git a/MCUME_teensy41/teensyaiie/teensyaiie.ino b/MCUME_teensy41/teensyaiie/teensyaiie.ino index fdd28ef..f3f60e1 100644 --- a/MCUME_teensy41/teensyaiie/teensyaiie.ino +++ b/MCUME_teensy41/teensyaiie/teensyaiie.ino @@ -3,132 +3,20 @@ extern "C" { #include "iopins.h" } -#include "aiie.h" - -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -TFT_T_DMA tft; -#else -#include "tft_t_dma.h" -TFT_T_DMA tft = TFT_T_DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, TFT_TOUCH_CS, TFT_TOUCH_INT); -#endif - -bool vgaMode = false; - -static unsigned char palette8[PALETTE_SIZE]; -static unsigned short palette16[PALETTE_SIZE]; -static IntervalTimer myTimer; -volatile boolean vbl=true; -static int skip=0; -static elapsedMicros tius; - -static void vblCount() { - if (vbl) { - vbl = false; - } else { - vbl = true; - } -} - -void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) -{ - if (index>8, - 320 & 0xFF, // YEND = 320 - ST7735_INVON , DELAY, // 7: hack - 10, - ST7735_NORON , DELAY, // 8: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 9: Main screen turn on, no args, w/delay - 255 -#endif -}; - -static void dmaInterrupt() { - dmatx.clearInterrupt(); - curTransfer++; - if (curTransfer >= nbTransfer) { - curTransfer = 0; - if (cancelled) { - dmatx.disable(); - rstop = 1; - } - } - arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2); -} - -static void setDmaStruct() { - uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; - int i=0; - uint16_t col=RGBVAL16(0x00,0x00,0x00);; - while (remaining > 0) { - uint16_t * fb = blocks[i]; - int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining); -#ifdef TFT_DEBUG - Serial.println((unsigned long)blocks[i]); - Serial.println(remaining); -#endif - switch (i) { - case 0: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb0[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0x00); -#endif - break; - case 1: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb1[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0xff); -#endif - break; - case 2: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb2[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0x00,0xff); -#endif - break; - case 3: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb3[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0xff,0x00,0xff); -#endif - break; - } - blocks[i] = fb; - if (blocks[i] == 0) { - Serial.print("ILI9341 allocaltion failed for block "); - Serial.println(i); - delay(10000); - } - - for (int j=0;jATTR_DST = 1; - dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); - dmasettings[i].interruptAtCompletion(); - remaining -= len; - i++; - } - dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); - nbTransfer = i; -#ifdef TFT_DEBUG - Serial.println(nbTransfer); -#endif -} - - -TFT_T_DMA::TFT_T_DMA(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso, uint8_t touch_cs, uint8_t touch_irq) -{ - _cs = cs; - _dc = dc; - _rst = rst; - _mosi = mosi; - _sclk = sclk; - _miso = miso; - pinMode(_dc, OUTPUT); - pinMode(_cs, OUTPUT); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); - if ( (touch_cs != 255) && (touch_irq != 255) ) { - _touch_irq = touch_irq; - _touch_cs = touch_cs; - pinMode(_touch_cs, OUTPUT); - pinMode(touch_irq, INPUT_PULLUP); - digitalWrite(_touch_cs, 1); - } -} - - -void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { - int dx=0; - int dy=0; -#ifdef ST7789 - if (TFT_REALWIDTH == TFT_REALHEIGHT) - { -#ifdef ROTATE_SCREEN - if (!flipped) { - dy += 80; - } -#else - if (flipped) { - dx += 80; - } -#endif - } -#endif - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - SPI.transfer16(x1+dx); - digitalWrite(_dc, 1); - SPI.transfer16(x2+dx); - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - digitalWrite(_dc, 1); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - return; - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - - SPI.transfer16(x1+dx); - SPI.transfer16(x2+dx); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - -void TFT_T_DMA::begin(void) { - SPI.setMOSI(_mosi); - SPI.setMISO(_miso); - SPI.setSCK(_sclk); - SPI.begin(); - - // Initialize display - if (_rst != 0xff) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - const uint8_t *addr = init_commands; - digitalWrite(_cs, 0); -#ifdef ILI9341 - while (1) { - uint8_t count = *addr++; - if (count-- == 0) break; - - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - - while (count-- > 0) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - } - - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(ILI9341_DISPON); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); -#endif -#ifdef ST7789 - uint8_t numCommands, numArgs; - uint16_t ms; - numCommands = *addr++; // Number of commands to follow - while(numCommands--) { // For each command... - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - numArgs = *addr++; // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs > 1) { // For each argument... - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - numArgs--; - } - - if (numArgs) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - if(ms) { - ms = *addr++; // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - digitalWrite(_cs, 1); - SPI.endTransaction(); - delay(ms); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - } - } - digitalWrite(_cs, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - SPI.endTransaction(); - - cancelled = false; - -#ifdef FLIP_SCREEN - flipscreen(true); -#else - flipscreen(false); -#endif -#ifdef ST7789 - if (TFT_REALWIDTH != TFT_REALHEIGHT) - { - flipscreen(true); - } -#endif -}; - - - -void TFT_T_DMA::flipscreen(bool flip) -{ - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(TFT_MADCTL); - digitalWrite(_dc, 1); - if (flip) { - flipped=true; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB); -#endif -#endif - } - else { - flipped=false; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB); -#endif -#endif - } - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - -boolean TFT_T_DMA::isflipped(void) -{ - return(flipped); -} - - -#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) - - -void TFT_T_DMA::startDMA(void) { - curTransfer = 0; - rstop = 0; - //dmatx.begin(true); - dmatx.attachInterrupt(dmaInterrupt); - setDmaStruct(); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - - digitalWrite(_cs, HIGH); - SPI.begin(); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); - - - LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: - LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX - LPSPIP_TCR = 15; // Framesize 16 Bits - //LPSPIP_FCR = 0; // Fifo Watermark - LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable - LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: - dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); - - dmatx = dmasettings[0]; - digitalWrite(_cs, 0); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - dmatx.enable(); -} - - -void TFT_T_DMA::stopDMA(void) { - rstop = 0; - wait(); - delay(50); - cancelled = false; - dmatx.detachInterrupt(); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - SPI.end(); -#ifdef ST7789 - begin(); -#endif -#ifdef ILI9341 - SPI.begin(); - digitalWrite(_cs, 0); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - SPI.endTransaction(); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); -} - -void TFT_T_DMA::wait(void) { - rstop = 1; - unsigned long m = millis(); - cancelled = true; - while (!rstop) { - if ((millis() - m) > 100) break; - delay(10); - asm volatile("wfi"); - }; - rstop = 0; -} - -int TFT_T_DMA::get_frame_buffer_size(int *width, int *height){ - if (width != nullptr) *width = TFT_REALWIDTH; - if (height != nullptr) *height = TFT_REALHEIGHT; - return TFT_REALWIDTH; -} - - -/*********************************************************************************************** - Touch functions - ***********************************************************************************************/ -/* Code based on ... - * - * @file XPT2046.cpp - * @date 19.02.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the XPT2046 driver for Arduino. - */ - -#define ADC_MAX 0x0fff - -void TFT_T_DMA::enableTouchIrq() -{ - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 }; - SPI.transfer((void*)&buf[0],3); - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); -} - -//Default callibration for non flipped -#define TX_MIN 30 -#define TY_MIN 20 -#define TX_MAX 300 -#define TY_MAX 220 - -//Default callibration for flipped -#define TFX_MIN 20 -#define TFY_MIN 25 -#define TFX_MAX 288 -#define TFY_MAX 221 - -static uint16_t txMin; -static uint16_t tyMin; -static uint16_t txMax; -static uint16_t tyMax; - - -void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { - if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) { - txMin = xMin; - tyMin = yMin; - txMax = xMax; - tyMax = yMax; - } - else { - if (flipped) { - txMin = TFX_MIN; - tyMin = TFY_MIN; - txMax = TFX_MAX; - tyMax = TFY_MAX; - } - else { - txMin = TX_MIN; - tyMin = TY_MIN; - txMax = TX_MAX; - tyMax = TY_MAX; - } - } -} - - -void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - if ( TOUCH_ENABLED() ) { - uint16_t x = 0; - uint16_t y = 0; - uint16_t z1 = 0; - uint16_t z2 = 0; - uint8_t i = 0; - int16_t xraw=0, yraw=0; - - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - - for(; i < 15; i++) { - // SPI requirer 32bit aliment - uint8_t buf[12] = { - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00 - }; - SPI.transfer(&buf[0], &buf[0], 12); - y += (buf[1] << 8 | buf[2])>>3; - x += (buf[4] << 8 | buf[5])>>3; - z1 += (buf[7] << 8 | buf[8])>>3; - z2 += (buf[10] << 8 | buf[11])>>3; - } - enableTouchIrq(); - - if(i == 0) { - *oX = 0; - *oY = 0; - *oZ = 0; - } - else { - x /= i; - y /= i; - z1 /= i; - z2 /= i; - } - - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); - int z = z1 + ADC_MAX - z2; - if (flipped) { - xraw = x; - yraw = y; - } else { - xraw = ADC_MAX - x; - yraw = ADC_MAX - y; - } - xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1); - yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1); - - *oX = xraw; - *oY = yraw; - *oZ = z; - } - else - { - *oX = 0; - *oY = 0; - *oZ = 0; - } -} - -void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - readRaw(oX,oY,oZ); - // callibrate ... - if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin); - if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin); - //Serial.print(*oX); - //Serial.print(" "); - //Serial.println(*oY); -} - - -/*********************************************************************************************** - No DMA functions - ***********************************************************************************************/ -void TFT_T_DMA::fillScreenNoDma(uint16_t color) { - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - int i,j; - for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(arx, ary, arx+arw-1, ary+arh-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - bits = *charpt++; - //digitalWrite(_dc, 1); - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - x +=8; -#ifdef ILI9341 - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); -#endif - digitalWrite(_cs, 1); - SPI.endTransaction(); - } - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - - - -/*********************************************************************************************** - DMA functions - ***********************************************************************************************/ -uint16_t * TFT_T_DMA::getLineBuffer(int j) -{ - uint16_t * block=blocks[j>>6]; - return(&block[(j&0x3F)*TFT_REALWIDTH]); -} - -void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) { - uint8_t *buffer=buf; - uint8_t *src; - - int i,j,y=0; - if (width*2 <= TFT_REALWIDTH) { - for (j=0; j>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH]; - for (i=0; i>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x]; - for (i=0; i>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - block=blocks[l>>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt++; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - x +=8; - } -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { - drawSprite(x,y,bitmap, 0,0,0,0); -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) -{ - int bmp_offx = 0; - int bmp_offy = 0; - uint16_t *bmp_ptr; - - int w =*bitmap++; - int h = *bitmap++; - - - if ( (arw == 0) || (arh == 0) ) { - // no crop window - arx = x; - ary = y; - arw = w; - arh = h; - } - else { - if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - int l=ary; - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx]; - bmp_ptr = (uint16_t*)bitmap; - for (int col=0;col -#include -#include -#endif - -#include "tft_t_dma_config.h" - -#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) -#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define R16(rgb) ((rgb>>8)&0xf8) -#define G16(rgb) ((rgb>>3)&0xfc) -#define B16(rgb) ((rgb<<3)&0xf8) - -#define PAL_COLOR_MASK 0xff - -#ifdef LOHRES -#define TFT_WIDTH 240 -#define TFT_REALWIDTH 240 -#else -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 -#endif -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - -//#define WIDTH 272 -//#define HEIGHT 228 - -#define LINES_PER_BLOCK 64 -#define NR_OF_BLOCK 4 -#define SCREEN_DMA_NUM_SETTINGS NR_OF_BLOCK - - -#ifdef ILI9341 - -#define ILI9341_NOP 0x00 -#define ILI9341_SWRESET 0x01 -#define ILI9341_RDDID 0x04 -#define ILI9341_RDDST 0x09 - -#define ILI9341_SLPIN 0x10 -#define ILI9341_SLPOUT 0x11 -#define ILI9341_PTLON 0x12 -#define ILI9341_NORON 0x13 - -#define ILI9341_RDMODE 0x0A -#define ILI9341_RDMADCTL 0x0B -#define ILI9341_RDPIXFMT 0x0C -#define ILI9341_RDIMGFMT 0x0D -#define ILI9341_RDSELFDIAG 0x0F - -#define ILI9341_INVOFF 0x20 -#define ILI9341_INVON 0x21 -#define ILI9341_GAMMASET 0x26 -#define ILI9341_DISPOFF 0x28 -#define ILI9341_DISPON 0x29 - -#define ILI9341_CASET 0x2A -#define ILI9341_PASET 0x2B -#define ILI9341_RAMWR 0x2C -#define ILI9341_RAMRD 0x2E - -#define ILI9341_PTLAR 0x30 -#define ILI9341_MADCTL 0x36 -#define ILI9341_VSCRSADD 0x37 -#define ILI9341_PIXFMT 0x3A - -#define ILI9341_FRMCTR1 0xB1 -#define ILI9341_FRMCTR2 0xB2 -#define ILI9341_FRMCTR3 0xB3 -#define ILI9341_INVCTR 0xB4 -#define ILI9341_DFUNCTR 0xB6 - -#define ILI9341_PWCTR1 0xC0 -#define ILI9341_PWCTR2 0xC1 -#define ILI9341_PWCTR3 0xC2 -#define ILI9341_PWCTR4 0xC3 -#define ILI9341_PWCTR5 0xC4 -#define ILI9341_VMCTR1 0xC5 -#define ILI9341_VMCTR2 0xC7 - -#define ILI9341_RDID1 0xDA -#define ILI9341_RDID2 0xDB -#define ILI9341_RDID3 0xDC -#define ILI9341_RDID4 0xDD - -#define ILI9341_GMCTRP1 0xE0 -#define ILI9341_GMCTRN1 0xE1 - -#define ILI9341_MADCTL_MY 0x80 -#define ILI9341_MADCTL_MX 0x40 -#define ILI9341_MADCTL_MV 0x20 -#define ILI9341_MADCTL_ML 0x10 -#define ILI9341_MADCTL_RGB 0x00 -#define ILI9341_MADCTL_BGR 0x08 -#define ILI9341_MADCTL_MH 0x04 - -#define TFT_CASET ILI9341_CASET -#define TFT_PASET ILI9341_PASET -#define TFT_RAMWR ILI9341_RAMWR -#define TFT_MADCTL ILI9341_MADCTL - -#endif - - -#ifdef ST7789 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_RGB 0x00 -#define ST77XX_MADCTL_BGR 0x08 -#define ST77XX_MADCTL_MH 0x04 - -#define TFT_CASET ST7735_CASET -#define TFT_PASET ST7735_RASET -#define TFT_RAMWR ST7735_RAMWR -#define TFT_MADCTL ST7735_MADCTL - -#endif - - - -#ifdef __cplusplus - -class TFT_T_DMA -{ - public: - TFT_T_DMA(uint8_t _CS, uint8_t _DC, uint8_t _RST = 255, uint8_t _MOSI=11, uint8_t _SCLK=13, uint8_t _MISO=12, uint8_t touch_cs=38, uint8_t touch_irq=37); - - void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); - void begin(void); - void flipscreen(bool flip); - boolean isflipped(void); - void startDMA(void); - void stopDMA(); - int get_frame_buffer_size(int *width, int *height); - - // Touch screen functions - #define TOUCH_ENABLED() ((_touch_cs != 255) && (_touch_irq != 255)) - bool isTouching(void) { return ((!TOUCH_ENABLED())?false:(digitalRead(_touch_irq) == LOW)); } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax); - - // NoDMA functions - void writeScreenNoDma(const uint16_t *pcolors); - void fillScreenNoDma(uint16_t color); - void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - // DMA functions - uint16_t * getLineBuffer(int j); - void writeScreen(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int y, uint16_t *buf); - void fillScreen(uint16_t color); - void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - protected: - uint8_t _rst, _cs, _dc; - uint8_t _miso, _mosi, _sclk; - uint8_t _touch_irq=255, _touch_cs=255; - bool flipped=false; - - void wait(void); - void enableTouchIrq(); -}; - -#endif -#endif - - diff --git a/MCUME_teensy41/teensyaiie/tft_t_dma_config.h b/MCUME_teensy41/teensyaiie/tft_t_dma_config.h deleted file mode 100644 index 354cf74..0000000 --- a/MCUME_teensy41/teensyaiie/tft_t_dma_config.h +++ /dev/null @@ -1,14 +0,0 @@ -#include "platform_config.h" - -//#define ST7789 1 -//#define ILI9341 1 - -#define TFT_LINEARINT 1 -#define LINEARINT_HACK 1 - -//#define FLIP_SCREEN 1 -//#define TFT_DEBUG 1 -#if defined(__IMXRT1052__) || defined(__IMXRT1062__) -//#define TFT_STATICFB 1 -#endif - diff --git a/MCUME_teensy41/teensyaiie/vga_t_dma.h b/MCUME_teensy41/teensyaiie/vga_t_dma.h deleted file mode 100644 index 81a986b..0000000 --- a/MCUME_teensy41/teensyaiie/vga_t_dma.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - Wrapping class to extend VGA_T4 to TFT_T_DMA -*/ - -#ifndef _VGA_T_DMAH_ -#define _VGA_T_DMAH_ - -#ifdef __cplusplus -#include -#endif - - -#define RGBVAL16(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) - - - - -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 - -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - - - -#ifdef __cplusplus - -class TFT_T_DMA: public VGA_T4 -{ - public: - // Fake touch screen functions - bool isTouching(void) { return false; } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { } - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { }; - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { } - - // fake DMA functions - void startDMA(void) { }; - void stopDMA(void) { }; - - // fake no DMA functions - void writeScreenNoDma(const vga_pixel *pcolors) { writeScreen(pcolors); } - void fillScreenNoDma(vga_pixel color) { clear(color); } - void drawTextNoDma(int16_t x, int16_t y, const char * text, vga_pixel fgcolor, vga_pixel bgcolor, bool doublesize) { drawText(x,y,text,fgcolor,bgcolor,doublesize); } - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, vga_pixel color) { drawRect(x, y, w, h, color); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap) { drawSprite(x, y, bitmap); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh) { drawSprite(x, y, bitmap, croparx, cropary, croparw, croparh); } -}; - - -#endif -#endif diff --git a/MCUME_teensy41/teensyaiie/aiie.cpp b/MCUME_teensy41/teensyaiie/wrapemu.cpp similarity index 93% rename from MCUME_teensy41/teensyaiie/aiie.cpp rename to MCUME_teensy41/teensyaiie/wrapemu.cpp index 2e6c885..683192a 100644 --- a/MCUME_teensy41/teensyaiie/aiie.cpp +++ b/MCUME_teensy41/teensyaiie/wrapemu.cpp @@ -174,39 +174,44 @@ void aiie_Step(void) #endif { if ( !(pik & MASK_JOY2_BTN) && (k & MASK_JOY2_BTN) ) { + g_keyboard->onPress(RA); g_keyboard->onPress(LA); } else if ( (pik & MASK_JOY2_BTN) && !(k & MASK_JOY2_BTN) ) { + g_keyboard->onRelease(RA); g_keyboard->onRelease(LA); - } + } if ( !(pik & MASK_JOY1_BTN) && (k & MASK_JOY1_BTN) ) { g_keyboard->onPress(RA); + g_keyboard->onPress(LA); + } else if ( (pik & MASK_JOY1_BTN) && !(k & MASK_JOY1_BTN) ) { g_keyboard->onRelease(RA); + g_keyboard->onRelease(LA); } - if (k & MASK_JOY2_RIGHT) { + if ( (k & MASK_JOY2_LEFT) || (k & MASK_JOY1_LEFT) ) { if (padxinc < 0) padxinc = 0; if (padxinc != +1) padxinc += 1; if (padx != 255) padx += padxinc; g_paddles->setPaddle0(padx); } - else if (k & MASK_JOY2_LEFT) { + else if ( (k & MASK_JOY2_RIGHT) || (k & MASK_JOY1_RIGHT) ) { if (padxinc > 0) padxinc = 0; if (padxinc != -1) padxinc -= 1; if (padx != 0) padx += padxinc; g_paddles->setPaddle0(padx); } - if (k & MASK_JOY2_UP) { + if ( (k & MASK_JOY2_UP) || (k & MASK_JOY1_UP) ) { if (padyinc < 0) padyinc = 0; if (padyinc != 1) padyinc += 1; if (pady != 255) pady += padyinc; g_paddles->setPaddle1(pady); } - else if (k & MASK_JOY2_DOWN) { + else if ( (k & MASK_JOY2_DOWN) || (k & MASK_JOY1_DOWN) ) { if (padyinc > 0) padyinc = 0; if (padyinc != -1) padyinc -= 1; if (pady != 0) pady += padyinc; diff --git a/MCUME_teensy41/teensyaiie/aiie.h b/MCUME_teensy41/teensyaiie/wrapemu.h similarity index 100% rename from MCUME_teensy41/teensyaiie/aiie.h rename to MCUME_teensy41/teensyaiie/wrapemu.h diff --git a/MCUME_teensy41/teensycastaway/.DS_Store b/MCUME_teensy41/teensycastaway/.DS_Store deleted file mode 100644 index 5008ddf..0000000 Binary files a/MCUME_teensy41/teensycastaway/.DS_Store and /dev/null differ diff --git a/MCUME_teensy41/teensycastaway/emuapi.cpp b/MCUME_teensy41/teensycastaway/emuapi.cpp index 68c0c1d..e128cca 100644 --- a/MCUME_teensy41/teensycastaway/emuapi.cpp +++ b/MCUME_teensy41/teensycastaway/emuapi.cpp @@ -5,25 +5,31 @@ extern "C" { #include "iopins.h" } -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#else -#include "tft_t_dma.h" -#endif +#include -#ifdef HAS_USBKEY +#ifdef HAS_USB #include "USBHost_t36.h" // Read this header first for key info USBHost myusb; USBHub hub1(myusb); +#ifdef HAS_USBKEY KeyboardController keyboard1(myusb); USBHIDParser hid1(myusb); MouseController mouse1(myusb); +#endif +#ifdef HAS_USBMIDI MIDIDevice midi1(myusb); #endif +#ifdef HAS_USBJOY +#define COUNT_JOYSTICKS 4 +JoystickController joysticks[COUNT_JOYSTICKS](myusb); +#endif +#endif static bool emu_writeConfig(void); static bool emu_readConfig(void); static bool emu_eraseConfig(void); +static bool emu_writeGfxConfig(char * display_type); +static int emu_readGfxConfig(void); static bool mouseDetected = false; static bool keyboardDetected = false; @@ -34,12 +40,13 @@ static File file; #define MAX_FILES 64 #define AUTORUN_FILENAME "autorun.txt" +#define GFX_CFG_FILENAME "gfxmode.txt" -#define MAX_FILENAME_SIZE 24 +#define MAX_FILENAME_SIZE 34 #define MAX_MENULINES 9 #define TEXT_HEIGHT 16 #define TEXT_WIDTH 8 -#define MENU_FILE_XOFFSET (6*TEXT_WIDTH) +#define MENU_FILE_XOFFSET (2*TEXT_WIDTH) #define MENU_FILE_YOFFSET (2*TEXT_HEIGHT) #define MENU_FILE_W (MAX_FILENAME_SIZE*TEXT_WIDTH) #define MENU_FILE_H (MAX_MENULINES*TEXT_HEIGHT) @@ -53,7 +60,8 @@ static File file; #define MENU_VGA_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) #define MENU_VGA_YOFFSET (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37) -extern TFT_T_DMA tft; +#include "t4_dsp.h" +T4_DSP tft; static int nbFiles=0; static int curFile=0; @@ -65,6 +73,8 @@ static char selected_filename[MAX_FILENAME_SIZE]=""; static char second_selected_filename[MAX_FILENAME_SIZE]=""; static bool menuRedraw=true; static bool autorun=false; +static bool vgahires=false; + static const unsigned short * keys; #ifdef TEECOMPUTER @@ -158,6 +168,29 @@ void emu_Free(void * pt) free(pt); } +#define SMEMPOOL (0x800000) +EXTMEM static unsigned char slowmem[SMEMPOOL]; +static int slowmempt = 0; + +void * emu_SMalloc(unsigned int size) +{ + void * mem = (void*)&slowmem[slowmempt]; + slowmempt += size; + + if ( slowmempt > SMEMPOOL ) { + mem = NULL; + emu_printf("failure to allocate slow"); + } + else { + emu_printf("could allocate slow static "); + emu_printf(size); + } + return mem; +} + +void emu_SFree(void * pt) +{ +} /******************************** * Input and keyboard ********************************/ @@ -329,6 +362,12 @@ int emu_ReadKeys(void) #endif if ( row & 0x02 ) retval |= MASK_JOY2_BTN; + +#ifdef EXTPAD + if ( sh_pressed ) retval |= MASK_KEY_USER3; + if ( fn_pressed ) retval |= MASK_KEY_USER1; + digitalWrite(KLED, 0); +#else // Handle LED flash uint32_t time_ms=millis(); if ((time_ms-last_t_ms) > 100) { @@ -412,8 +451,9 @@ int emu_ReadKeys(void) if ( key_fn ) retval |= MASK_KEY_USER2; if ( ( key_fn ) && (keymatrix[4] == 0x10 )) retval |= MASK_KEY_USER1; +#endif - if ( (key_fn) && (key_sh) ) + if ( (fn_pressed) && (sh_pressed) ) #else if ( ((retval & (MASK_KEY_USER1+MASK_KEY_USER2)) == (MASK_KEY_USER1+MASK_KEY_USER2)) || (retval & MASK_KEY_USER4 ) ) @@ -453,8 +493,10 @@ int emu_ReadKeys(void) while (true) { ; } -#endif +#endif } + + emu_GetJoystick(); return (retval); } @@ -607,7 +649,7 @@ int emu_setKeymap(int index) { } int emu_GetMouse(int *x, int *y, int *buts) { -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBKEY) if (mouse1.available()) { *buts = mouse1.getButtons(); *x = mouse1.getMouseX(); @@ -620,7 +662,23 @@ int emu_GetMouse(int *x, int *y, int *buts) { return 0; } -#ifdef HAS_USBKEY +int emu_GetJoystick(void) { +#if defined(HAS_USB) && (HAS_USBJOY) + for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) { + if (joysticks[joystick_index].available()) { + uint64_t axis_mask = joysticks[joystick_index].axisMask(); + uint64_t axis_changed_mask = joysticks[joystick_index].axisChangedMask(); + uint32_t buttons = joysticks[joystick_index].getButtons(); + Serial.printf("Joystick(%d): buttons = %x", joystick_index, buttons); + Serial.println(); + } + } + return 1; +#endif + return 0; +} + +#if defined(HAS_USB) && (HAS_USBKEY) void OnPress(auto key) { keyboardDetected = true; @@ -764,7 +822,7 @@ int emu_KeyboardDetected(void) { return (keyboardDetected?1:0); } -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) static unsigned char midiBuffer[16]; static unsigned char midiLastCmd=0; static int midiDataCnt=0; @@ -772,8 +830,7 @@ static int midiCmdNbParam=0; #endif void emu_MidiOnDataReceived(unsigned char value) { - -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) //Serial.println(value, HEX); //10000000 = 128 = note off //10010000 = 144 = note on @@ -941,6 +998,7 @@ void emu_MidiOnDataReceived(unsigned char value) { /******************************** * Menu file loader UI ********************************/ +#ifdef FILEBROWSER static int readNbFiles(void) { int totalFiles = 0; @@ -970,8 +1028,6 @@ static int readNbFiles(void) { return totalFiles; } - - void backgroundMenu(void) { menuRedraw=true; tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00)); @@ -981,11 +1037,13 @@ void backgroundMenu(void) { int handleMenu(uint16_t bClick) { if (autorun) { + toggleMenu(false); + menuRedraw=false; return (ACTION_RUN1); } int action = ACTION_NONE; - if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) ) { + if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) || ( bClick & MASK_KEY_USER2 ) ) { char newpath[MAX_FILENAME_PATH]; strcpy(newpath, selection); strcat(newpath, "/"); @@ -996,17 +1054,31 @@ int handleMenu(uint16_t bClick) File file = SD.open(selection); if (file.isDirectory()) { curFile = 0; - nbFiles = readNbFiles(); + nbFiles = readNbFiles(); + menuRedraw=true; } - else { - action = ACTION_RUN1; + else + { #ifdef TEECOMPUTER - if (key_extmode) { + if ( (key_extmode) || ( key_sh) ) { emu_writeConfig(); } + if ( tft.getMode() < MODE_VGA_320x240) { + if ( bClick & MASK_KEY_USER2 ) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + } + //emu_SwapJoysticks(0); #endif + toggleMenu(false); + menuRedraw=false; + return (ACTION_RUN1); } - menuRedraw=true; } else if ( bClick & MASK_KEY_USER1 ) { menuRedraw=true; @@ -1015,24 +1087,14 @@ int handleMenu(uint16_t bClick) strcat(second_selection, "/"); strcat(second_selection, second_selected_filename); action = ACTION_RUN2; - } - else if ( bClick & MASK_KEY_USER2 ) { - menuRedraw=true; - char newpath[MAX_FILENAME_PATH]; - strcpy(newpath, selection); - strcat(newpath, "/"); - strcat(newpath, selected_filename); - strcpy(selection,newpath); - action = ACTION_RUN3; - //emu_SwapJoysticks(0); - } + } else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) { if (curFile!=0) { menuRedraw=true; curFile--; } } - else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { + else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { if ((curFile-9)>=0) { menuRedraw=true; curFile -= 9; @@ -1047,7 +1109,7 @@ int handleMenu(uint16_t bClick) menuRedraw=true; } } - else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { + else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { if ((curFile<(nbFiles-9)) && (nbFiles)) { curFile += 9; menuRedraw=true; @@ -1104,12 +1166,12 @@ int handleMenu(uint16_t bClick) return (action); } -bool menuActive(void) +int menuActive(void) { - return (menuOn); + return (menuOn?1:0); } -void toggleMenu(bool on) { +void toggleMenu(int on) { if (on) { menuOn=true; backgroundMenu(); @@ -1127,7 +1189,7 @@ char * menuSecondSelection(void) { return (second_selection); } - +#endif /******************************** * OSKB handling @@ -1145,8 +1207,9 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) char c[4] = {' ',0,' ',0}; const char * cpt = str; int i=0; - int fb_width,fb_height; - tft.get_frame_buffer_size(&fb_width, &fb_height); + int fb_width,fb_height,fbstride; + + fbstride = tft.get_frame_buffer_size(&fb_width, &fb_height); int ypos = (bottom?(fb_height-2*8):0); int line = row + (bottom?2:0); while ((c[1] = *cpt++)) @@ -1155,7 +1218,7 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0); else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff); if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff); - tft.drawTextNoDma(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); + tft.drawText(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); i++; } } @@ -1253,7 +1316,7 @@ int handleOSKB(void) { return retval; } -void toggleOSKB(bool forceon) { +void toggleOSKB(int forceon) { if (forceon) { oskbOn = true; drawOSKB(); @@ -1302,7 +1365,7 @@ int emu_FileOpen(const char * filepath, const char * mode) // emu_printf(filepath); #ifdef HCFH int retval = 0; - if ((file = SD.open(filepath, O_READ | O_WRITE))) { + if ((file = SD.open(filepath, O_READ))) { retval = 1; } else { @@ -1313,7 +1376,7 @@ int emu_FileOpen(const char * filepath, const char * mode) int retval = 0; int handler = getFreeFileHandler(); if (handler >= 0) { - if ((file_handlers[handler] = SD.open(filepath, O_READ | O_WRITE))) { + if ((file_handlers[handler] = SD.open(filepath, O_READ))) { // emu_printi(handler+1); retval = handler+1; } @@ -1420,6 +1483,9 @@ unsigned int emu_FileSize(const char * filepath) emu_printf(filesize); lofile.close(); } + else { + emu_printf("filesize failed"); + } return(filesize); } @@ -1505,6 +1571,48 @@ static bool emu_eraseConfig(void) SD.remove (ROMSDIR "/" AUTORUN_FILENAME); } +static bool emu_writeGfxConfig(char * display_type) +{ + bool retval = false; + SD.remove ("/" GFX_CFG_FILENAME); + if (strcmp(display_type, "VGA")) { + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(display_type, strlen(display_type)) != strlen(display_type)) { + emu_printf("GFX config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + } + return retval; +} + +#define CFG_VGA 0 +#define CFG_ILI 1 +#define CFG_ST 2 + +static int emu_readGfxConfig(void) +{ + int retval = CFG_VGA; // No file = VGA + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + if (filesize == 2) // "ST" + { + retval = CFG_ST; + } + else if (filesize == 3) // "ILI" + { + retval = CFG_ILI; + } + lofile.close(); + } + return retval; +} + /******************************** * File IO compatibility ********************************/ @@ -1686,62 +1794,249 @@ FRESULT f_mkdir (const char* path) /******************************** - * Initialization + * GFX wrapper ********************************/ -void emu_init(void) +static unsigned short palette16[PALETTE_SIZE]; +static IntervalTimer myTimer; +volatile boolean vbl=true; +volatile boolean vgatimervsync=false; +static void (*vblCallback)(void) = nullptr; +static int skip=0; + +static void vblCount() { + if (vbl) { + vbl = false; + } else { + vbl = true; + } +} + +void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) +{ + if (index= MODE_VGA_320x240 ) { + if (vgatimervsync) { + while (vbl==vb) {}; + } + else { + tft.waitSync(); + } + } + else { + while (vbl==vb) {}; + } + if (vblCallback != nullptr) { + vblCallback(); + } +} + +void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride) +{ + if (skip == 0) { + tft.writeScreenPal(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); + } +} +void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLinePal(width,height,line, VBuf, palette16); + } +} + +void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine(width,height,line, VBuf); + } +} + +void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine8(width,height,line, VBuf, palette16); + } +} + +int emu_IsVga(void) +{ + return (tft.getMode() >= MODE_VGA_320x240?1:0); +} + +int emu_IsVgaHires(void) +{ + return (tft.getMode() >= MODE_VGA_640x240?1:0); +} + +int emu_FrameSkip(void) +{ + return skip; +} + + +/******************************** + * AUDIO wrapper +********************************/ +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +AudioPlaySystem mymixer; + +void emu_sndInit() { + Serial.println("sound init"); + mymixer.begin_audio(256, mymixer.snd_Mixer); + mymixer.start(); +} + +void emu_sndPlaySound(int chan, int volume, int freq) +{ + if (chan < 6) { + mymixer.sound(chan, freq, volume); + } + /* + Serial.print(chan); + Serial.print(":" ); + Serial.print(volume); + Serial.print(":" ); + Serial.println(freq); + */ +} + +void emu_sndPlayBuzz(int size, int val) { + mymixer.buzz(size,val); + //Serial.print((val==1)?1:0); + //Serial.print(":"); + //Serial.println(size); +} +#endif + +/******************************** + * Initialization +********************************/ +void emu_init(int hires) { Serial.begin(115200); + vgahires = hires; -#ifdef HAS_USBKEY +#ifdef HAS_USB myusb.begin(); +#ifdef HAS_USBKEY keyboard1.attachPress(OnPress); keyboard1.attachRelease(OnRelease); #endif +#endif - while (!SD.begin(SD_CS)) +#ifdef FILEBROWSER + if (!SD.begin(SD_CS)) { - Serial.println("SD begin failed, retrying..."); - delay(1000); + Serial.println("No SD card detected"); } strcpy(selection,ROMSDIR); - FileHandlersInit(); - nbFiles = readNbFiles(); - - Serial.print("SD initialized, files found: "); Serial.println(nbFiles); +#endif emu_InitJoysticks(); #ifdef SWAP_JOYSTICK - joySwapped = true; + joySwapped = true; #else - joySwapped = false; + joySwapped = false; #endif -#ifdef TEECOMPUTER -#ifndef HAS_T4_VGA - tft.flipscreen(false); -#endif -#endif int keypressed = emu_ReadKeys(); +#ifdef HAS_T4_VGA + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } +#else + int gfx_mode = CFG_VGA; // default +#ifdef FILEBROWSER + gfx_mode = emu_readGfxConfig(); +#endif + // Force VGA if UP pressed + if (keypressed & MASK_JOY2_UP) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("VGA"); +#endif + gfx_mode = CFG_VGA; + } + else { + if (keypressed & MASK_JOY2_LEFT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ST"); +#endif + gfx_mode = CFG_ST; + } + else if (keypressed & MASK_JOY2_RIGHT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ILI"); +#endif + gfx_mode = CFG_ILI; + } + } + if (gfx_mode == CFG_VGA) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + else + { + tft.begin(gfx_mode == CFG_ILI?MODE_TFTILI_320x240:MODE_TFTST_320x240); + } +#endif + if (keypressed & MASK_JOY2_DOWN) { tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) ); tft.drawTextNoDma(64,48, (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); +#ifdef FILEBROWSER emu_eraseConfig(); delay(1000); +#endif } else { +#ifdef FILEBROWSER if (emu_readConfig()) { autorun = true; } +#endif } +#ifdef FILEBROWSER toggleMenu(true); +#endif } -void emu_start(void) +void emu_start(int vblms, void * callback, int forcetimervsync) { + vgatimervsync = forcetimervsync?true:false; + tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); + tft.startRefresh(); + if (callback != nullptr) { + vblCallback = callback; + } + + myTimer.begin(vblCount, vblms); +#ifdef HAS_SND + emu_sndInit(); +#endif usbnavpad = 0; } diff --git a/MCUME_teensy41/teensycastaway/emuapi.h b/MCUME_teensy41/teensycastaway/emuapi.h index f2f5ea5..5dd6130 100644 --- a/MCUME_teensy41/teensycastaway/emuapi.h +++ b/MCUME_teensy41/teensycastaway/emuapi.h @@ -2,148 +2,14 @@ #define EMUAPI_H #include "platform_config.h" - -#define CUSTOM_SND 1 -//#define TIMER_REND 1 - -#define EXTRA_HEAP 0x10 - -// Title: < > -#define TITLE " AtariST Emulator " -#define ROMSDIR "/st" - -#define emu_Init(FLOPPY1, FLOPPY2, MODE) {ast_Init(); ast_Start(FLOPPY1, FLOPPY2, MODE);} -#define emu_Step(x) {ast_Step();} -#define emu_Input(x) {ast_Input(x);} - -#define MAX_FILENAME_PATH 64 -#define NB_FILE_HANDLER 4 -#define PALETTE_SIZE 256 -#define VID_FRAME_SKIP 0x0 -#define TFT_VBUFFER_YCROP 0 -#define SINGLELINE_RENDERING 1 - -#define R32(rgb) ((rgb>>16)&0xff) -#define G32(rgb) ((rgb>>8)&0xff) -#define B32(rgb) (rgb & 0xff) +#include "emucfg.h" #define ACTION_NONE 0 -#define ACTION_MAXKBDVAL 16 -#define ACTION_EXITKBD 128 -#define ACTION_RUN1 129 -#define ACTION_RUN2 130 -#define ACTION_RUN3 131 - -#ifdef KEYMAP_PRESENT - -/* -const unsigned short key_map1[] = { - 11,12,13,14,15,16,17,18,19,20, 39, - 0, 21,22,23,24,25,26,27,28,29,30, - 0, 31,32,33,34,35,36,37,60,40, - 66,68,69,67 //U L R D - }; - -const unsigned short key_map2[] = { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,0, - 0, 0,0,0,0,0,53,0,51,52,54, - 0, 61,62,0,59,0,0,0,38,58, - 66,68,69,67 - }; - -const unsigned short key_map3[] = { - 40,41,42,43,44,45,46,47,48,49, 0, // function keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 63,64,0,0,0,0,0,58,65, - 66,68,69,67 - }; -*/ - -#define keylables_map0_0 (char *)"qwertyuiop\x1a" -#define keylables_map0_1 (char *)" asdfghjkl\x19" -#define keylables_map0_2 (char *)" zxcvbnm,.;/" -#define keylables_map0_3 (char *)" +\x10-" -const unsigned short key_map0[] = { - 'q','w','e','r','t','y','u','i','o','p',127, //lowecase - 0,'a','s','d','f','g','h','j','k','l',10, - 0,'z','x','c','v','b','n','m',',','.',';','/', - 218,216,215,217, //U L R D - 0,'+',' ','-' - }; - -#define keylables_map1_0 (char *)"QWERTYUIOP@" -#define keylables_map1_1 (char *)" ASDFGHJKL\x19" -#define keylables_map1_2 (char *)" ZXCVBNM<>:?" -#define keylables_map1_3 (char *)" =\x10_" -const unsigned short key_map1[] = { - 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase - 0,'A','S','D','F','G','H','J','K','L',10, - 0,'Z','X','C','V','B','N','M','<','>',':','?', - 218,216,215,217, //U L R D - 0,'=',' ','_' - }; - -#define keylables_map2_0 (char *)"!\"#$%^&*()@" -#define keylables_map2_1 (char *)" |\\[]{} " -#define keylables_map2_2 (char *)" <>:?" -#define keylables_map2_3 (char *)" =\x10_" -const unsigned short key_map2[] = { - '!','"','#','$','%','^','&','*','(',')','@', // shiftothers - 0, '|','\\','[',']','{','}','\'',0,0,0, - 0, 0,0,0,0,0,0,0,'<','>',':','?', - 218,216,215,217, //U L R D - 0,'=',' ','_' - }; - -#define keylables_map3_0 (char *)"1234567890 " -#define keylables_map3_1 (char *)" " -#define keylables_map3_2 (char *)" " -#define keylables_map3_3 (char *)" " - -const unsigned short key_map3[] = { - '1','2','3','4','5','6','7','8','9','0',0, // digit keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 218,216,215,217, //U L R D - 0,0,' ',0 - }; - -#define keylables_map4_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " -#define keylables_map4_1 (char *)" " -#define keylables_map4_2 (char *)" " -#define keylables_map4_3 (char *)" " - -const unsigned short key_map4[] = { - 194,195,196,197,198,199,200,201,202,203, 0, // function keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 218,216,215,217, //U L R D - 0,0,' ',0 - }; - -#define keylables_map5_0 (char *)" " -#define keylables_map5_1 (char *)" " -#define keylables_map5_2 (char *)" " -#define keylables_map5_3 (char *)" " - -const unsigned short key_map5[] = { - 0,0,0,0,0,0,0,0,0,0,0, // extra keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 218,216,215,217, //U L R D - 0,0,' ',0 - }; - -const unsigned short matkeys[] = { - 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 - 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 - 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 - 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN - 0x510,0x010,0x110,0x310, // row 4 - }; - -#endif +#define ACTION_RUN1 1 +#define ACTION_RUN2 2 +#define FORCE_VGATIMERVSYNC 1 +#define SUPPORT_HIRES 1 #define MASK_JOY2_RIGHT 0x0001 #define MASK_JOY2_LEFT 0x0002 @@ -160,20 +26,21 @@ const unsigned short matkeys[] = { #define MASK_JOY1_BTN 0x1000 #define MASK_KEY_USER4 0x2000 - +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) #ifdef __cplusplus extern "C" { +extern void emu_init(int hires=0); +extern void emu_start(int vblms, void * callback, int forcetimervsync=0); #endif - -extern void emu_init(void); -extern void emu_start(void); extern void emu_printf(const char * text); extern void emu_printi(int val); extern void emu_printh(int val); extern void * emu_Malloc(unsigned int size); extern void * emu_MallocI(unsigned int size); extern void emu_Free(void * pt); +extern void * emu_SMalloc(unsigned int size); +extern void emu_SFree(void * pt); extern int emu_FileOpen(const char * filepath, const char * mode); extern int emu_FileRead(void * buf, int size, int handler); @@ -188,25 +55,23 @@ extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size); extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek); extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index); -extern void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride); -extern void emu_DrawLine(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line); extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line); +extern void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride); extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line); -extern void emu_CopyLine(int width, int height, int ysrc, int ydst); extern void emu_DrawVsync(void); extern int emu_FrameSkip(void); -extern void * emu_LineBuffer(int line); -extern void emu_tweakVideo(int shiftdelta, int numdelta, int denomdelta); -extern void emu_DrawWaitLine(int line); +extern int emu_IsVga(void); +extern int emu_IsVgaHires(void); -extern bool menuActive(void); +extern int menuActive(void); extern char * menuSelection(void); extern char * menuSecondSelection(void); -extern void toggleMenu(bool on); +extern void toggleMenu(int on); extern int handleMenu(unsigned short bClick); extern int handleOSKB(void); -extern void toggleOSKB(bool forceon); +extern void toggleOSKB(int forceon); extern void emu_InitJoysticks(void); extern int emu_SwapJoysticks(int statusOnly); @@ -215,6 +80,7 @@ extern int emu_ReadKeys(void); extern int emu_GetPad(void); extern int emu_GetMouse(int *x, int *y, int *buts); extern int emu_MouseDetected(void); +extern int emu_GetJoystick(void); extern int emu_KeyboardDetected(void); extern int emu_ReadAnalogJoyX(int min, int max); extern int emu_ReadAnalogJoyY(int min, int max); diff --git a/MCUME_teensy41/teensycastaway/emucfg.h b/MCUME_teensy41/teensycastaway/emucfg.h new file mode 100644 index 0000000..73d3196 --- /dev/null +++ b/MCUME_teensy41/teensycastaway/emucfg.h @@ -0,0 +1,137 @@ +#ifndef EMUCFG_H +#define EMUCFG_H + +#include "wrapemu.h" + +// Title: < > +#define TITLE " AtariST Emulator " +#define ROMSDIR "/st" + +#define emu_Init(FLOPPY1, FLOPPY2, MODE) {ast_Init(); ast_Start(FLOPPY1, FLOPPY2, MODE);} +#define emu_Step(x) {ast_Step();} +#define emu_Input(x) {ast_Input(x);} + +#define MAX_FILENAME_PATH 64 +#define NB_FILE_HANDLER 4 + +#define PALETTE_SIZE 256 +#define VID_FRAME_SKIP 0x0 +#define TFT_VBUFFER_YCROP 0 +#define SINGLELINE_RENDERING 1 +#define CUSTOM_SND 1 +//#define TIMER_REND 1 +//#define EXTPAD 1 +#define EXTRA_HEAP 0x10 +#define FILEBROWSER 1 + + +#ifdef KEYMAP_PRESENT + +/* +const unsigned short key_map1[] = { + 11,12,13,14,15,16,17,18,19,20, 39, + 0, 21,22,23,24,25,26,27,28,29,30, + 0, 31,32,33,34,35,36,37,60,40, + 66,68,69,67 //U L R D + }; + +const unsigned short key_map2[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,0, + 0, 0,0,0,0,0,53,0,51,52,54, + 0, 61,62,0,59,0,0,0,38,58, + 66,68,69,67 + }; + +const unsigned short key_map3[] = { + 40,41,42,43,44,45,46,47,48,49, 0, // function keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 63,64,0,0,0,0,0,58,65, + 66,68,69,67 + }; +*/ + +#define keylables_map0_0 (char *)"qwertyuiop\x1a" +#define keylables_map0_1 (char *)" asdfghjkl\x19" +#define keylables_map0_2 (char *)" zxcvbnm,.;/" +#define keylables_map0_3 (char *)" +\x10-" +const unsigned short key_map0[] = { + 'q','w','e','r','t','y','u','i','o','p',127, //lowecase + 0,'a','s','d','f','g','h','j','k','l',10, + 0,'z','x','c','v','b','n','m',',','.',';','/', + 218,216,215,217, //U L R D + 0,'+',' ','-' + }; + +#define keylables_map1_0 (char *)"1234567890 " +#define keylables_map1_1 (char *)" " +#define keylables_map1_2 (char *)" " +#define keylables_map1_3 (char *)" " +const unsigned short key_map1[] = { + '1','2','3','4','5','6','7','8','9','0',0, // digit keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 218,216,215,217, //U L R D + 0,0,' ',0 + }; + +#define keylables_map2_0 (char *)"!\"#$%^&*()@" +#define keylables_map2_1 (char *)" |\\[]{} " +#define keylables_map2_2 (char *)" <>:?" +#define keylables_map2_3 (char *)" =\x10_" +const unsigned short key_map2[] = { + '!','"','#','$','%','^','&','*','(',')','@', // shiftothers + 0, '|','\\','[',']','{','}','\'',0,0,0, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 218,216,215,217, //U L R D + 0,'=',' ','_' + }; + +#define keylables_map3_0 (char *)"QWERTYUIOP@" +#define keylables_map3_1 (char *)" ASDFGHJKL\x19" +#define keylables_map3_2 (char *)" ZXCVBNM<>:?" +#define keylables_map3_3 (char *)" =\x10_" +const unsigned short key_map3[] = { + 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase + 0,'A','S','D','F','G','H','J','K','L',10, + 0,'Z','X','C','V','B','N','M','<','>',':','?', + 218,216,215,217, //U L R D + 0,'=',' ','_' + }; + +#define keylables_map4_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " +#define keylables_map4_1 (char *)" " +#define keylables_map4_2 (char *)" " +#define keylables_map4_3 (char *)" " + +const unsigned short key_map4[] = { + 194,195,196,197,198,199,200,201,202,203, 0, // function keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 218,216,215,217, //U L R D + 0,0,' ',0 + }; + +#define keylables_map5_0 (char *)" " +#define keylables_map5_1 (char *)" " +#define keylables_map5_2 (char *)" " +#define keylables_map5_3 (char *)" " + +const unsigned short key_map5[] = { + 0,0,0,0,0,0,0,0,0,0,0, // extra keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 218,216,215,217, //U L R D + 0,0,' ',0 + }; + +const unsigned short matkeys[] = { + 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 + 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 + 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 + 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN + 0x510,0x010,0x110,0x310, // row 4 + }; + +#endif + +#endif diff --git a/MCUME_teensy41/teensycastaway/platform_config.h b/MCUME_teensy41/teensycastaway/platform_config.h index beb49d8..dd983cd 100644 --- a/MCUME_teensy41/teensycastaway/platform_config.h +++ b/MCUME_teensy41/teensycastaway/platform_config.h @@ -4,24 +4,26 @@ #define TEECOMPUTER 1 #ifdef TEECOMPUTER - -//#define ILI9341 1 -//#define ST7789 1 -//#define TFTSPI1 1 -#define HAS_T4_VGA 1 -#define HIRES 1 +#define TFTSPI1 1 +//#define HAS_T4_VGA 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 +#define HAS_MOUSE 1 +#define HAS_MIDI 1 #define PT8211 1 #else #define HAS_T4_VGA 1 -#define HIRES 1 //#define INVX 1 #define INVY 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 +#define HAS_MOUSE 1 +#define HAS_MIDI 1 +#define PT8211 1 #endif diff --git a/MCUME_teensy41/teensycastaway/t4_dsp.cpp b/MCUME_teensy41/teensycastaway/t4_dsp.cpp new file mode 100644 index 0000000..43301fa --- /dev/null +++ b/MCUME_teensy41/teensycastaway/t4_dsp.cpp @@ -0,0 +1,1774 @@ +/* + TFT/VGA driver + DMA TFT driver based on C64 ILI9341 dma driver from Frank Bösing, 2017 +*/ + +#include "T4_DSP.h" + +#include +#include + +#include "font8x8.h" + +// TFT constants and variables +#define TFT_LINEARINT 1 +#define LINEARINT_HACK 1 +#define DMA_LINES_PER_BLOCK 64 +#define DMA_NUM_SETTINGS 4 + +#define TFT_SWRESET 0x01 +#define TFT_SLPOUT 0x11 +#define TFT_INVON 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_MADCTL 0x36 +#define TFT_PIXFMT 0x3A +#define TFT_MADCTL_MY 0x80 +#define TFT_MADCTL_MX 0x40 +#define TFT_MADCTL_MV 0x20 +#define TFT_MADCTL_ML 0x10 +#define TFT_MADCTL_RGB 0x00 +#define TFT_MADCTL_BGR 0x08 +#define TFT_MADCTL_MH 0x04 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) +//#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) +//#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) +//#define R16(rgb) ((rgb>>8)&0xf8) +//#define G16(rgb) ((rgb>>3)&0xfc) +//#define B16(rgb) ((rgb<<3)&0xf8) + +// LPSPI4 = SPI0 in Teensy 4.0 +// LPSPI3 = SPI1 in Teensy 4.0 +// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) + +#ifdef TFTSPI1 +#define SPI SPI1 +#define LPSPIP_TDR LPSPI3_TDR +#define LPSPIP_CR LPSPI3_CR +#define LPSPIP_CFGR1 LPSPI3_CFGR1 +#define LPSPIP_TCR LPSPI3_TCR +#define LPSPIP_DER LPSPI3_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX +#else +#define LPSPIP_TDR LPSPI4_TDR +#define LPSPIP_CR LPSPI4_CR +#define LPSPIP_CFGR1 LPSPI4_CFGR1 +#define LPSPIP_TCR LPSPI4_TCR +#define LPSPIP_DER LPSPI4_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX +#endif + +#define SPICLOCK 60000000 +#define SPI_MODE SPI_MODE0 + +// VGA constants and macros +typedef uint8_t vga_pixel; +#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) + +static DMASetting dmasettings[DMA_NUM_SETTINGS]; +static DMAChannel dmatx; +static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K +static volatile uint8_t rstop = 0; +static volatile bool cancelled = false; +static volatile uint8_t curTransfer = 0; +static uint8_t nbTransfer = 0; +static uint16_t * tft_buffer; +static int tft_width; +static int tft_height; +static int tft_stride; + +#define DELAY_MASK 0x80 +PROGMEM static const uint8_t init_commands[] = { + 1+DELAY_MASK, TFT_SWRESET, 150, + 1+DELAY_MASK, TFT_SLPOUT, 255, + 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, + 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, + 1, TFT_INVON, + 1, TFT_DISPON, + 0 +}; + +// VGA constants and variables +// Objective: +// generates VGA signal fully in hardware with as little as possible CPU help + +// Principle: +// QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) +// 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate +// RGB out, combined to create 8bits(/12bits) output. + +// Note: +// - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels +// - experimental resolution: 352x240,352x480 +// - experimental resolution: 512x240,512x480 (not stable) +// - video memory is allocated using malloc in T4 heap +// - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing +// but tried to be compensated by pixel shifting +// - Default is 8bits RRRGGGBB (332) +// But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! +// - Only ok at 600MHz else some disturbances visible + + + +#define TOP_BORDER 40 +#define PIN_HBLANK 15 + +#define PIN_R_B2 33 +#define PIN_R_B1 4 +#define PIN_R_B0 3 +#define PIN_G_B2 2 +#define PIN_G_B1 13 +#define PIN_G_B0 11 +#define PIN_B_B1 12 +#define PIN_B_B0 10 + + +#define DMA_HACK 0x80 + +#define R16(rgb) ((rgb>>8)&0xf8) +#define G16(rgb) ((rgb>>3)&0xfc) +#define B16(rgb) ((rgb<<3)&0xf8) + +// VGA 640x480@60Hz +// Screen refresh rate 60 Hz +// Vertical refresh 31.46875 kHz +// Pixel freq. 25.175 MHz +// +// Visible area 640 25.422045680238 us +// Front porch 16 0.63555114200596 us +// Sync pulse 96 3.8133068520357 us +// Back porch 48 1.9066534260179 us +// Whole line 800 31.777557100298 us + +#define frame_freq 60.0 // Hz +#define line_freq 31.46875 // KHz +#define pix_freq (line_freq*800) // KHz (25.175 MHz) + +// pix_period = 39.7ns +// H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) +#define frontporch_pix 20 //16 +#define backporch_pix 44 //48 + +// Flexio Clock +// PLL3 SW CLOCK (3) => 480 MHz +// PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) +#define FLEXIO_CLK_SEL_PLL3 3 +#define FLEXIO_CLK_SEL_PLL5 2 + +/* Set video PLL */ +// There are /1, /2, /4, /8, /16 post dividers for the Video PLL. +// The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, +// and CCM_ANALOG_MISC2 register sets according to the following equation. +// PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + +// nfact: +// This field controls the PLL loop divider. +// Valid range for DIV_SELECT divider value: 27~54. + +#define POST_DIV_SELECT 2 + +// Full buffer including back/front porch +static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; +static uint32_t dstbuffer __attribute__((aligned(32))); + +// Visible vuffer +static vga_pixel * vga_buffer; +static int vga_width; +static int vga_height; +static int vga_stride; + +static int maxpixperline; +static int left_border; +static int right_border; +static int line_double; +static int pix_shift; +static int ref_div_select; +static int ref_freq_num; +static int ref_freq_denom; +static int ref_pix_shift; +static int combine_shiftreg; + +#ifdef DEBUG +static uint32_t ISRTicks_prev = 0; +volatile uint32_t ISRTicks = 0; +#endif + +uint8_t T4_DSP::_rst; +uint8_t T4_DSP::_cs; +uint8_t T4_DSP::_dc; +uint8_t T4_DSP::_mosi; +uint8_t T4_DSP::_sclk; +uint8_t T4_DSP::_vsync_pin = -1; +DMAChannel T4_DSP::flexio1DMA; +DMAChannel T4_DSP::flexio2DMA; + +static volatile uint32_t VSYNC = 0; +static volatile uint32_t currentLine=0; +#define NOP asm volatile("nop\n\t"); +static gfx_mode_t gfxmode = MODE_UNDEFINED; + + +FASTRUN void T4_DSP::TFT_isr(void) { + dmatx.clearInterrupt(); + curTransfer++; + if (curTransfer >= nbTransfer) { + curTransfer = 0; + if (cancelled) { + dmatx.disable(); + rstop = 1; + } + } + arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); +} + +FASTRUN void T4_DSP::QT3_isr(void) { + TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); + TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); + + cli(); + + // V-PULSE + if (currentLine > 0) { + digitalWrite(_vsync_pin, 1); + VSYNC = 0; + } else { + digitalWrite(_vsync_pin, 0); + VSYNC = 1; + } + + currentLine++; + currentLine = currentLine % 525; + + + uint32_t y = (currentLine - TOP_BORDER) >> line_double; + // Visible area + + if (y >= 0 && y < vga_height) { + // Disable DMAs + //DMA_CERQ = flexio2DMA.channel; + //DMA_CERQ = flexio1DMA.channel; + + // Setup source adress + // Aligned 32 bits copy + unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; + flexio2DMA.TCD->SADDR = p; + if (pix_shift & DMA_HACK) + { + // Unaligned copy + uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; + flexio1DMA.TCD->SADDR = p2; + } + else { + p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 + flexio1DMA.TCD->SADDR = p; + } + + // Enable DMAs + //flexio2DMA.enable(); + //flexio1DMA.enable(); + DMA_SERQ = flexio2DMA.channel; + DMA_SERQ = flexio1DMA.channel; + arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); + } + sei(); + +#ifdef DEBUG + ISRTicks++; +#endif + asm volatile("dsb"); +} + +static void setDmaStruct() { + uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; + uint16_t * fb = (uint16_t*)malloc(remaining); + tft_buffer = fb; + tft_width = TFT_WIDTH; + tft_height = TFT_HEIGHT; + tft_stride = TFT_WIDTH; + uint16_t col=RGBVAL16(0x00,0x00,0x00); + int i=0; + while (remaining > 0) { + int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); + blocks[i] = fb; + for (int j=0;jATTR_DST = 1; + dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); + dmasettings[i].interruptAtCompletion(); + fb += len/2; + remaining -= len; + i++; + } + dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); + nbTransfer = i; +} + +static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 +{ +//if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; + CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE + | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 + | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); + CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; + CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock + const int div_post_pll = 1; // other values: 2,4 + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass +} + +T4_DSP::T4_DSP() +{ + _cs = TFT_CS; + _dc = TFT_DC; + _rst = TFT_RST; + _mosi = TFT_MOSI; + _sclk = TFT_SCLK; + pinMode(_dc, OUTPUT); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, 1); + digitalWrite(_dc, 1); + _vsync_pin = 8; +} + + +void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { + int dx=0; + int dy=0; + digitalWrite(_dc, 0); + SPI.transfer(TFT_CASET); + digitalWrite(_dc, 1); + SPI.transfer16(x1+dx); + digitalWrite(_dc, 1); + SPI.transfer16(x2+dx); + digitalWrite(_dc, 0); + SPI.transfer(TFT_PASET); + digitalWrite(_dc, 1); + SPI.transfer16(y1+dy); + digitalWrite(_dc, 1); + SPI.transfer16(y2+dy); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + return; +} + +void T4_DSP::tft_setup(bool isST) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + // RESET if reset pin defined + if (_rst != 0xff) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + const uint8_t *addr = init_commands; + uint8_t count; + digitalWrite(_cs, 0); + while (count = *addr++) { + uint8_t command = *addr++; + if ( (command == TFT_INVON) && (!isST) ) { + // Skip TFT_INVON for ILI + } + else { + digitalWrite(_dc, 0); // command + SPI.transfer(command); + uint16_t ms = count & DELAY_MASK; + count &= ~DELAY_MASK; + while (--count > 0) { // data + uint8_t data = *addr++; + if ( (command == TFT_MADCTL) && (isST) ) { + data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; + } + digitalWrite(_dc, 1); + SPI.transfer(data); + } + if (ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + digitalWrite(_cs, 1); + SPI.endTransaction(); + delay(2); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + } + } + } + digitalWrite(_cs, 1); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + SPI.endTransaction(); + /* + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_dc, 0); + digitalWrite(_cs, 0); + SPI.transfer(TFT_MADCTL); + digitalWrite(_dc, 1); + SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); + // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); + digitalWrite(_cs, 1); + SPI.endTransaction(); + */ + cancelled = false; +} + +// display VGA image +gfx_error_t T4_DSP::begin(gfx_mode_t mode) +{ + uint32_t flexio_clock_div; + combine_shiftreg = 0; +// int div_select = 49; +// int num = 135; +// int denom = 100; + int div_select = 20; + int num = 9800; + int denom = 10000; + int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; + int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; + set_videoClock(div_select,num,denom,true); + +#ifdef DEBUG + Serial.println(mode); + Serial.println("mode"); +#endif + + switch(mode) + { + case MODE_TFTILI_320x240: +#ifdef DEBUG + Serial.println("TFTILI_320x240"); +#endif + tft_setup(false); + gfxmode = mode; + break; + case MODE_TFTST_320x240: +#ifdef DEBUG + Serial.println("TFTST_320x240"); +#endif + tft_setup(true); + gfxmode = mode; + break; + + case MODE_VGA_320x240: +#ifdef DEBUG + Serial.println("VGA_320x240"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_320x480: +#ifdef DEBUG + Serial.println("VGA_320x480"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_640x240: +#ifdef DEBUG + Serial.println("VGA_640x240"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/pix_freq; + line_double = 1; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_640x480: +#ifdef DEBUG + Serial.println("VGA_640x480"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = (flexio_freq/pix_freq); + line_double = 0; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_512x240: +#ifdef DEBUG + Serial.println("VGA_512x240"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 1; + pix_shift = 0; + break; + + case MODE_VGA_512x480: +#ifdef DEBUG + Serial.println("VGA_512x480"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 0; + pix_shift = 0; + break; + + case MODE_VGA_352x240: +#ifdef DEBUG + Serial.println("VGA_352x240"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_352x480: +#ifdef DEBUG + Serial.println("VGA_352x480"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + } + + if (mode >= MODE_VGA_320x240) + { + if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { + fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); + digitalWrite(_cs, 0); + digitalWrite(_dc, 0); + SPI.transfer(TFT_DISPOFF); + digitalWrite(_cs, 1); + delay(20); + digitalWrite(_cs, 0); + digitalWrite(_cs, 1); + } + gfxmode = mode; + + maxpixperline = vga_stride; + // Save param for tweek adjustment + ref_div_select = div_select; + ref_freq_num = num; + ref_freq_denom = denom; + ref_pix_shift = pix_shift; + +#ifdef DEBUG + Serial.println("frequency"); + Serial.println(flexio_freq); + Serial.println("div"); + Serial.println(flexio_freq/pix_freq); +#endif + + pinMode(_vsync_pin, OUTPUT); + pinMode(PIN_HBLANK, OUTPUT); + + /* Basic pin setup FlexIO1 */ + pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 + pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 + pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 + pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 + /* Basic pin setup FlexIO2 */ + pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 + pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 + pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 + pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 + + /* High speed and drive strength configuration */ + *(portControlRegister(PIN_G_B2)) = 0xFF; + *(portControlRegister(PIN_R_B0)) = 0xFF; + *(portControlRegister(PIN_R_B1)) = 0xFF; + *(portControlRegister(PIN_R_B2)) = 0xFF; + *(portControlRegister(PIN_B_B0)) = 0xFF; + *(portControlRegister(PIN_B_B1)) = 0xFF; + *(portControlRegister(PIN_G_B0)) = 0xFF; + *(portControlRegister(PIN_G_B1)) = 0xFF; + + /* Set clock for FlexIO1 and FlexIO2 */ + CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) + | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); + CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) + | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); + + + /* Set up pin mux FlexIO1 */ + *(portConfigRegister(PIN_G_B2)) = 0x14; + *(portConfigRegister(PIN_R_B0)) = 0x14; + *(portConfigRegister(PIN_R_B1)) = 0x14; + *(portConfigRegister(PIN_R_B2)) = 0x14; + /* Set up pin mux FlexIO2 */ + *(portConfigRegister(PIN_B_B0)) = 0x14; + *(portConfigRegister(PIN_B_B1)) = 0x14; + *(portConfigRegister(PIN_G_B0)) = 0x14; + *(portConfigRegister(PIN_G_B1)) = 0x14; + + /* Enable the clock */ + CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + /* Enable the FlexIO with fast access */ + FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + + uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; + uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; + + /* Shifter 0 registers for FlexIO2 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 + inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter + stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled + startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable + timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 + timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock + pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output + pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity + shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode + /* Shifter 0 registers for FlexIO1 */ + FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + /* Shifter 0 registers for FlexIO1 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 + FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + if (combine_shiftreg) { + pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled + FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + } + /* Timer 0 registers for FlexIO2 */ + timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset + timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output + timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset + timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare + timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert + stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled + startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled + if (combine_shiftreg) { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag + } + else { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag + } + triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low + triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected + pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled + //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 + //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high + timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode + // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) + + int shifts_per_transfer; + if (combine_shiftreg) { + shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 + } + else { + shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 + } + FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); + /* Timer 0 registers for FlexIO1 */ + FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); +#ifdef DEBUG + Serial.println("FlexIO setup complete"); +#endif + + /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ + if (combine_shiftreg) { + FLEXIO2_SHIFTSDEN |= (1<<1); + FLEXIO1_SHIFTSDEN |= (1<<1); + } + else { + FLEXIO2_SHIFTSDEN |= (1<<0); + FLEXIO1_SHIFTSDEN |= (1<<0); + } + /* Disable DMA channel so it doesn't start transferring yet */ + flexio1DMA.disable(); + flexio2DMA.disable(); + /* Set up DMA channel to use Shifter 0 trigger */ + flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); + flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); + + + if (combine_shiftreg) { + flexio2DMA.TCD->NBYTES = 8; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 8; + flexio2DMA.TCD->CITER = maxpixperline / 8; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + flexio1DMA.TCD->NBYTES = 8; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 8; + flexio1DMA.TCD->CITER = maxpixperline / 8; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Setup DMA2 Flexio2 copy + flexio2DMA.TCD->NBYTES = 4; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 4; + flexio2DMA.TCD->CITER = maxpixperline / 4; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + // Setup DMA1 Flexio1 copy + // Use pixel shift to avoid color smearing? + if (pix_shift & DMA_HACK) + { + if (pix_shift & 0x3 == 0) { + // Aligned 32 bits copy (32bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Unaligned (source) 32 bits copy (8bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 1; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion + } + } + else + { + // Aligned 32 bits copy + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + } + +#ifdef DEBUG + Serial.println("DMA setup complete"); +#endif + + // enable clocks for QTIMER3: generates the 15KHz for hsync + // Pulse: + // low : 3.8133 us => 569x6.7ns + // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) + // (OLD TEST) + // (4us low, 28us high => 32us) + // (597x6.7ns for 4us) + // (4179x6.7ns for 28us) + CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 + //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 + + #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz + #define MARGIN_D 1000 + + TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer + // Invert output pin as we want the interupt on rising edge + TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) + TMR3_CNTR3 = 0; + TMR3_LOAD3 = 0; + + /* Inverted timings */ + unsigned long long cpu_freq = F_CPU; + unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; + int rate2 = rate; + + int substract = 1; + if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { + substract=5; + rate2=1652; + } + + #ifdef DEBUG + Serial.print("MARGIN_N is: "); + Serial.println(rate2, DEC); + Serial.print("SUBSTRACT is: "); + Serial.println(substract, DEC); +#endif + TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; + TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; + /* + TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; + */ + TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on + TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), + // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) + //configure Teensy pin Compare output + IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 + attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function + NVIC_ENABLE_IRQ(IRQ_QTIMER3); +#ifdef DEBUG + Serial.println("QTIMER3 setup complete"); + Serial.print("V-PIN is "); + Serial.println(_vsync_pin); +#endif + + /* initialize gfx buffer */ + if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift + if (gfxbuffer == NULL) return(GFX_ERROR); +#ifdef DEBUG + Serial.println("Memory allocated"); +#endif + + memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); + vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; +#ifdef DEBUG + Serial.println(vga_stride); + Serial.println(vga_height); + Serial.println("Screen cleared"); +#endif + } + + return(GFX_OK); +} + +gfx_mode_t T4_DSP::getMode(void) +{ + return gfxmode; +} + +void T4_DSP::startRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + curTransfer = 0; + rstop = 0; + //dmatx.begin(true); + dmatx.attachInterrupt(TFT_isr); + setDmaStruct(); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + + digitalWrite(_cs, HIGH); + SPI.begin(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + + LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: + LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX + LPSPIP_TCR = 15; // Framesize 16 Bits + //LPSPIP_FCR = 0; // Fifo Watermark + LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable + LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: + dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); + + dmatx = dmasettings[0]; + digitalWrite(_cs, 0); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + dmatx.enable(); + } +} + + +void T4_DSP::stopRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + rstop = 1; + unsigned long m = millis(); + cancelled = true; + while (!rstop) { + if ((millis() - m) > 100) break; + delay(10); + asm volatile("wfi"); + }; + rstop = 0; + delay(50); + cancelled = false; + dmatx.detachInterrupt(); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + SPI.end(); +#ifdef ST7789 +// begin(gfxmode); +#endif + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + } +} + +int T4_DSP::get_frame_buffer_size(int *width, int *height) { + if (gfxmode < MODE_VGA_320x240) { + if (width != nullptr) *width = tft_width; + if (height != nullptr) *height = tft_height; + return tft_stride; + } + else { + if (width != nullptr) *width = vga_width; + if (height != nullptr) *height = vga_height; + return vga_stride; + } +} + +void T4_DSP::waitSync() +{ + if (gfxmode >= MODE_VGA_320x240) { + while (VSYNC == 0) {}; + } +} + +void T4_DSP::waitLine(int line) +{ + if (gfxmode >= MODE_VGA_320x240) { + while (currentLine != line) {}; + } +} + +/*********************************************************************************************** + No DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreenNoDma(uint16_t color) { + if (gfxmode < MODE_VGA_320x240) { + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + int i,j; + for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(arx, ary, arx+arw-1, ary+arh-1); + bitmap = bitmap + bmp_offy*w + bmp_offx; + for (int row=0;row> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + bits = *charpt++; + //digitalWrite(_dc, 1); + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + x +=8; + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + else { + drawText(x, y, text, fgcolor, bgcolor, doublesize); + } +} + + +/*********************************************************************************************** + DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreen(uint16_t color) { + int i,j; + if (gfxmode < MODE_VGA_320x240) { + for (j=0; j> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + dst=&tft_buffer[l*tft_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + x +=8; + } + } + else { + vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); + vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); + vga_pixel * dst; + while ((c = *text++)) { + const unsigned char * charpt=&font8x8[c][0]; + int l=y; + for (int i=0;i<8;i++) + { + unsigned char bits; + if (doublesize) { + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + x +=8; + } + } +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { + drawSprite(x,y,bitmap, 0,0,0,0); +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) +{ + int bmp_offx = 0; + int bmp_offy = 0; + uint16_t *bmp_ptr; + int w =*bitmap++; + int h = *bitmap++; + if ( (arw == 0) || (arh == 0) ) { + // no crop window + arx = x; + ary = y; + arw = w; + arh = h; + } + else { + if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + int l=ary; + bitmap = bitmap + bmp_offy*w + bmp_offx; + + if (gfxmode < MODE_VGA_320x240) { + for (int row=0;row tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]; + pos +=step; + } + #endif + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i 2) ) y += (tft_height-height)/2; + uint16_t * dst=&tft_buffer[y*tft_stride]; + if (width > tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]]; + pos +=step; + } +#endif + } + else if ((width*2) == tft_width) { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]]; + *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i tft_width) { + int step = ((width << 8)/tft_width); + int pos = 0; + for (int i=0; i> 8]]; + pos +=step; + } + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = pix; + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i +#include +#endif + +#include "platform_config.h" +#include "iopins.h" + + + +#ifndef TFT_WIDTH +#define TFT_WIDTH 320 +#endif +#define TFT_REALWIDTH 320 + +#ifndef TFT_HEIGHT +#define TFT_HEIGHT 240 +#endif +#define TFT_REALHEIGHT 240 + + +typedef enum gfx_mode_t +{ + MODE_UNDEFINED = 0, + MODE_TFTILI_320x240 = 1, + MODE_TFTST_320x240 = 2, + MODE_VGA_320x240 = 3, + MODE_VGA_320x480 = 4, + MODE_VGA_352x240 = 5, + MODE_VGA_352x480 = 6, + MODE_VGA_512x240 = 7, + MODE_VGA_512x480 = 8, + MODE_VGA_640x240 = 9, + MODE_VGA_640x480 = 10 +} gfx_mode_t; + +typedef enum gfx_error_t +{ + GFX_OK = 0, + GFX_ERROR = -1 +} gfx_error_t; + + +#ifdef __cplusplus + +class T4_DSP +{ + public: + T4_DSP(); + + gfx_error_t begin(gfx_mode_t mode); + gfx_mode_t getMode(void); + void startRefresh(void); + void stopRefresh(); + + int get_frame_buffer_size(int *width, int *height); + void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); + + // wait next Vsync + void waitSync(); + void waitLine(int line); + + // NoDMA functions + void fillScreenNoDma(uint16_t color); + void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + // DMA functions + void fillScreen(uint16_t color); + void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + void writeLine(int width, int height, int y, uint16_t *buf); + void writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + void writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16); + void writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + + protected: + static uint8_t _rst, _cs, _dc; + static uint8_t _mosi, _sclk; + static uint8_t _vsync_pin; + static DMAChannel flexio1DMA; + static DMAChannel flexio2DMA; + void tft_setup(bool isST); + static void TFT_isr(void); + static void QT3_isr(void); +}; + +#endif +#endif diff --git a/MCUME_teensy41/teensycastaway/teensycastaway.ino b/MCUME_teensy41/teensycastaway/teensycastaway.ino index cae9a02..531acbd 100644 --- a/MCUME_teensy41/teensycastaway/teensycastaway.ino +++ b/MCUME_teensy41/teensycastaway/teensycastaway.ino @@ -3,233 +3,42 @@ extern "C" { #include "emuapi.h" } -#include "test.h" - -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -TFT_T_DMA tft; -#else -#include "tft_t_dma.h" -TFT_T_DMA tft = TFT_T_DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, TFT_TOUCH_CS, TFT_TOUCH_INT); -#endif - -bool vgaMode = false; - -static unsigned char palette8[PALETTE_SIZE]; -static unsigned short palette16[PALETTE_SIZE]; -static IntervalTimer myTimer; -volatile boolean vbl=true; -static int skip=0; -static elapsedMicros tius; - -static void vblCount() { - if (vbl) { - vbl = false; - } else { - vbl = true; - } -} - -void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) -{ - if (index>8, - 320 & 0xFF, // YEND = 320 - ST7735_INVON , DELAY, // 7: hack - 10, - ST7735_NORON , DELAY, // 8: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 9: Main screen turn on, no args, w/delay - 255 -#endif -}; - -static void dmaInterrupt() { - dmatx.clearInterrupt(); - curTransfer++; - if (curTransfer >= nbTransfer) { - curTransfer = 0; - if (cancelled) { - dmatx.disable(); - rstop = 1; - } - } - arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2); -} - -static void setDmaStruct() { - uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; - int i=0; - uint16_t col=RGBVAL16(0x00,0x00,0x00);; - while (remaining > 0) { - uint16_t * fb = blocks[i]; - int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining); -#ifdef TFT_DEBUG - Serial.println((unsigned long)blocks[i]); - Serial.println(remaining); -#endif - switch (i) { - case 0: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb0[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0x00); -#endif - break; - case 1: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb1[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0xff); -#endif - break; - case 2: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb2[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0x00,0xff); -#endif - break; - case 3: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb3[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0xff,0x00,0xff); -#endif - break; - } - blocks[i] = fb; - if (blocks[i] == 0) { - Serial.print("ILI9341 allocaltion failed for block "); - Serial.println(i); - delay(10000); - } - - for (int j=0;jATTR_DST = 1; - dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); - dmasettings[i].interruptAtCompletion(); - remaining -= len; - i++; - } - dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); - nbTransfer = i; -#ifdef TFT_DEBUG - Serial.println(nbTransfer); -#endif -} - - -TFT_T_DMA::TFT_T_DMA(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso, uint8_t touch_cs, uint8_t touch_irq) -{ - _cs = cs; - _dc = dc; - _rst = rst; - _mosi = mosi; - _sclk = sclk; - _miso = miso; - pinMode(_dc, OUTPUT); - pinMode(_cs, OUTPUT); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); - if ( (touch_cs != 255) && (touch_irq != 255) ) { - _touch_irq = touch_irq; - _touch_cs = touch_cs; - pinMode(_touch_cs, OUTPUT); - pinMode(touch_irq, INPUT_PULLUP); - digitalWrite(_touch_cs, 1); - } -} - - -void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { - int dx=0; - int dy=0; -#ifdef ST7789 - if (TFT_REALWIDTH == TFT_REALHEIGHT) - { -#ifdef ROTATE_SCREEN - if (!flipped) { - dy += 80; - } -#else - if (flipped) { - dx += 80; - } -#endif - } -#endif - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - SPI.transfer16(x1+dx); - digitalWrite(_dc, 1); - SPI.transfer16(x2+dx); - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - digitalWrite(_dc, 1); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - return; - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - - SPI.transfer16(x1+dx); - SPI.transfer16(x2+dx); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - -void TFT_T_DMA::begin(void) { - SPI.setMOSI(_mosi); - SPI.setMISO(_miso); - SPI.setSCK(_sclk); - SPI.begin(); - - // Initialize display - if (_rst != 0xff) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - const uint8_t *addr = init_commands; - digitalWrite(_cs, 0); -#ifdef ILI9341 - while (1) { - uint8_t count = *addr++; - if (count-- == 0) break; - - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - - while (count-- > 0) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - } - - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(ILI9341_DISPON); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); -#endif -#ifdef ST7789 - uint8_t numCommands, numArgs; - uint16_t ms; - numCommands = *addr++; // Number of commands to follow - while(numCommands--) { // For each command... - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - numArgs = *addr++; // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs > 1) { // For each argument... - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - numArgs--; - } - - if (numArgs) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - if(ms) { - ms = *addr++; // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - digitalWrite(_cs, 1); - SPI.endTransaction(); - delay(ms); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - } - } - digitalWrite(_cs, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - SPI.endTransaction(); - - cancelled = false; - -#ifdef FLIP_SCREEN - flipscreen(true); -#else - flipscreen(false); -#endif -#ifdef ST7789 - if (TFT_REALWIDTH != TFT_REALHEIGHT) - { - flipscreen(true); - } -#endif -}; - - - -void TFT_T_DMA::flipscreen(bool flip) -{ - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(TFT_MADCTL); - digitalWrite(_dc, 1); - if (flip) { - flipped=true; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB); -#endif -#endif - } - else { - flipped=false; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB); -#endif -#endif - } - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - -boolean TFT_T_DMA::isflipped(void) -{ - return(flipped); -} - - -#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) - - -void TFT_T_DMA::startDMA(void) { - curTransfer = 0; - rstop = 0; - //dmatx.begin(true); - dmatx.attachInterrupt(dmaInterrupt); - setDmaStruct(); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - - digitalWrite(_cs, HIGH); - SPI.begin(); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); - - - LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: - LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX - LPSPIP_TCR = 15; // Framesize 16 Bits - //LPSPIP_FCR = 0; // Fifo Watermark - LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable - LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: - dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); - - dmatx = dmasettings[0]; - digitalWrite(_cs, 0); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - dmatx.enable(); -} - - -void TFT_T_DMA::stopDMA(void) { - rstop = 0; - wait(); - delay(50); - cancelled = false; - dmatx.detachInterrupt(); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - SPI.end(); -#ifdef ST7789 - begin(); -#endif -#ifdef ILI9341 - SPI.begin(); - digitalWrite(_cs, 0); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - SPI.endTransaction(); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); -} - -void TFT_T_DMA::wait(void) { - rstop = 1; - unsigned long m = millis(); - cancelled = true; - while (!rstop) { - if ((millis() - m) > 100) break; - delay(10); - asm volatile("wfi"); - }; - rstop = 0; -} - -int TFT_T_DMA::get_frame_buffer_size(int *width, int *height){ - if (width != nullptr) *width = TFT_REALWIDTH; - if (height != nullptr) *height = TFT_REALHEIGHT; - return TFT_REALWIDTH; -} - - -/*********************************************************************************************** - Touch functions - ***********************************************************************************************/ -/* Code based on ... - * - * @file XPT2046.cpp - * @date 19.02.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the XPT2046 driver for Arduino. - */ - -#define ADC_MAX 0x0fff - -void TFT_T_DMA::enableTouchIrq() -{ - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 }; - SPI.transfer((void*)&buf[0],3); - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); -} - -//Default callibration for non flipped -#define TX_MIN 30 -#define TY_MIN 20 -#define TX_MAX 300 -#define TY_MAX 220 - -//Default callibration for flipped -#define TFX_MIN 20 -#define TFY_MIN 25 -#define TFX_MAX 288 -#define TFY_MAX 221 - -static uint16_t txMin; -static uint16_t tyMin; -static uint16_t txMax; -static uint16_t tyMax; - - -void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { - if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) { - txMin = xMin; - tyMin = yMin; - txMax = xMax; - tyMax = yMax; - } - else { - if (flipped) { - txMin = TFX_MIN; - tyMin = TFY_MIN; - txMax = TFX_MAX; - tyMax = TFY_MAX; - } - else { - txMin = TX_MIN; - tyMin = TY_MIN; - txMax = TX_MAX; - tyMax = TY_MAX; - } - } -} - - -void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - if ( TOUCH_ENABLED() ) { - uint16_t x = 0; - uint16_t y = 0; - uint16_t z1 = 0; - uint16_t z2 = 0; - uint8_t i = 0; - int16_t xraw=0, yraw=0; - - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - - for(; i < 15; i++) { - // SPI requirer 32bit aliment - uint8_t buf[12] = { - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00 - }; - SPI.transfer(&buf[0], &buf[0], 12); - y += (buf[1] << 8 | buf[2])>>3; - x += (buf[4] << 8 | buf[5])>>3; - z1 += (buf[7] << 8 | buf[8])>>3; - z2 += (buf[10] << 8 | buf[11])>>3; - } - enableTouchIrq(); - - if(i == 0) { - *oX = 0; - *oY = 0; - *oZ = 0; - } - else { - x /= i; - y /= i; - z1 /= i; - z2 /= i; - } - - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); - int z = z1 + ADC_MAX - z2; - if (flipped) { - xraw = x; - yraw = y; - } else { - xraw = ADC_MAX - x; - yraw = ADC_MAX - y; - } - xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1); - yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1); - - *oX = xraw; - *oY = yraw; - *oZ = z; - } - else - { - *oX = 0; - *oY = 0; - *oZ = 0; - } -} - -void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - readRaw(oX,oY,oZ); - // callibrate ... - if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin); - if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin); - //Serial.print(*oX); - //Serial.print(" "); - //Serial.println(*oY); -} - - -/*********************************************************************************************** - No DMA functions - ***********************************************************************************************/ -void TFT_T_DMA::fillScreenNoDma(uint16_t color) { - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - int i,j; - for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(arx, ary, arx+arw-1, ary+arh-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - bits = *charpt++; - //digitalWrite(_dc, 1); - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - x +=8; -#ifdef ILI9341 - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); -#endif - digitalWrite(_cs, 1); - SPI.endTransaction(); - } - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - - - -/*********************************************************************************************** - DMA functions - ***********************************************************************************************/ -uint16_t * TFT_T_DMA::getLineBuffer(int j) -{ - uint16_t * block=blocks[j>>6]; - return(&block[(j&0x3F)*TFT_REALWIDTH]); -} - -void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) { - uint8_t *buffer=buf; - uint8_t *src; - - int i,j,y=0; - if (width*2 <= TFT_REALWIDTH) { - for (j=0; j>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH]; - for (i=0; i>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x]; - for (i=0; i>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - block=blocks[l>>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt++; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - x +=8; - } -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { - drawSprite(x,y,bitmap, 0,0,0,0); -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) -{ - int bmp_offx = 0; - int bmp_offy = 0; - uint16_t *bmp_ptr; - - int w =*bitmap++; - int h = *bitmap++; - - - if ( (arw == 0) || (arh == 0) ) { - // no crop window - arx = x; - ary = y; - arw = w; - arh = h; - } - else { - if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - int l=ary; - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx]; - bmp_ptr = (uint16_t*)bitmap; - for (int col=0;col -#include -#include -#endif - -#include "tft_t_dma_config.h" - -#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) -#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define R16(rgb) ((rgb>>8)&0xf8) -#define G16(rgb) ((rgb>>3)&0xfc) -#define B16(rgb) ((rgb<<3)&0xf8) - -#define PAL_COLOR_MASK 0xff - -#ifdef LOHRES -#define TFT_WIDTH 240 -#define TFT_REALWIDTH 240 -#else -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 -#endif -#define TFT_HEIGHT 200 -#define TFT_REALHEIGHT 240 - -//#define WIDTH 272 -//#define HEIGHT 228 - -#define LINES_PER_BLOCK 64 -#define NR_OF_BLOCK 4 -#define SCREEN_DMA_NUM_SETTINGS NR_OF_BLOCK - - -#ifdef ILI9341 - -#define ILI9341_NOP 0x00 -#define ILI9341_SWRESET 0x01 -#define ILI9341_RDDID 0x04 -#define ILI9341_RDDST 0x09 - -#define ILI9341_SLPIN 0x10 -#define ILI9341_SLPOUT 0x11 -#define ILI9341_PTLON 0x12 -#define ILI9341_NORON 0x13 - -#define ILI9341_RDMODE 0x0A -#define ILI9341_RDMADCTL 0x0B -#define ILI9341_RDPIXFMT 0x0C -#define ILI9341_RDIMGFMT 0x0D -#define ILI9341_RDSELFDIAG 0x0F - -#define ILI9341_INVOFF 0x20 -#define ILI9341_INVON 0x21 -#define ILI9341_GAMMASET 0x26 -#define ILI9341_DISPOFF 0x28 -#define ILI9341_DISPON 0x29 - -#define ILI9341_CASET 0x2A -#define ILI9341_PASET 0x2B -#define ILI9341_RAMWR 0x2C -#define ILI9341_RAMRD 0x2E - -#define ILI9341_PTLAR 0x30 -#define ILI9341_MADCTL 0x36 -#define ILI9341_VSCRSADD 0x37 -#define ILI9341_PIXFMT 0x3A - -#define ILI9341_FRMCTR1 0xB1 -#define ILI9341_FRMCTR2 0xB2 -#define ILI9341_FRMCTR3 0xB3 -#define ILI9341_INVCTR 0xB4 -#define ILI9341_DFUNCTR 0xB6 - -#define ILI9341_PWCTR1 0xC0 -#define ILI9341_PWCTR2 0xC1 -#define ILI9341_PWCTR3 0xC2 -#define ILI9341_PWCTR4 0xC3 -#define ILI9341_PWCTR5 0xC4 -#define ILI9341_VMCTR1 0xC5 -#define ILI9341_VMCTR2 0xC7 - -#define ILI9341_RDID1 0xDA -#define ILI9341_RDID2 0xDB -#define ILI9341_RDID3 0xDC -#define ILI9341_RDID4 0xDD - -#define ILI9341_GMCTRP1 0xE0 -#define ILI9341_GMCTRN1 0xE1 - -#define ILI9341_MADCTL_MY 0x80 -#define ILI9341_MADCTL_MX 0x40 -#define ILI9341_MADCTL_MV 0x20 -#define ILI9341_MADCTL_ML 0x10 -#define ILI9341_MADCTL_RGB 0x00 -#define ILI9341_MADCTL_BGR 0x08 -#define ILI9341_MADCTL_MH 0x04 - -#define TFT_CASET ILI9341_CASET -#define TFT_PASET ILI9341_PASET -#define TFT_RAMWR ILI9341_RAMWR -#define TFT_MADCTL ILI9341_MADCTL - -#endif - - -#ifdef ST7789 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_RGB 0x00 -#define ST77XX_MADCTL_BGR 0x08 -#define ST77XX_MADCTL_MH 0x04 - -#define TFT_CASET ST7735_CASET -#define TFT_PASET ST7735_RASET -#define TFT_RAMWR ST7735_RAMWR -#define TFT_MADCTL ST7735_MADCTL - -#endif - - - -#ifdef __cplusplus - -class TFT_T_DMA -{ - public: - TFT_T_DMA(uint8_t _CS, uint8_t _DC, uint8_t _RST = 255, uint8_t _MOSI=11, uint8_t _SCLK=13, uint8_t _MISO=12, uint8_t touch_cs=38, uint8_t touch_irq=37); - - void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); - void begin(void); - void flipscreen(bool flip); - boolean isflipped(void); - void startDMA(void); - void stopDMA(); - int get_frame_buffer_size(int *width, int *height); - - // Touch screen functions - #define TOUCH_ENABLED() ((_touch_cs != 255) && (_touch_irq != 255)) - bool isTouching(void) { return ((!TOUCH_ENABLED())?false:(digitalRead(_touch_irq) == LOW)); } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax); - - // NoDMA functions - void writeScreenNoDma(const uint16_t *pcolors); - void fillScreenNoDma(uint16_t color); - void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - // DMA functions - uint16_t * getLineBuffer(int j); - void writeScreen(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int y, uint16_t *buf); - void fillScreen(uint16_t color); - void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - protected: - uint8_t _rst, _cs, _dc; - uint8_t _miso, _mosi, _sclk; - uint8_t _touch_irq=255, _touch_cs=255; - bool flipped=false; - - void wait(void); - void enableTouchIrq(); -}; - -#endif -#endif - - diff --git a/MCUME_teensy41/teensycastaway/tft_t_dma_config.h b/MCUME_teensy41/teensycastaway/tft_t_dma_config.h deleted file mode 100644 index 0a712da..0000000 --- a/MCUME_teensy41/teensycastaway/tft_t_dma_config.h +++ /dev/null @@ -1,13 +0,0 @@ -#include "platform_config.h" - -//#define ST7789 1 -//#define ILI9341 1 - -#define TFT_LINEARINT 1 -#define LINEARINT_HACK 1 - -//#define FLIP_SCREEN 1 -//#define TFT_DEBUG 1 -#if defined(__IMXRT1052__) || defined(__IMXRT1062__) -//#define TFT_STATICFB 1 -#endif diff --git a/MCUME_teensy41/teensycastaway/vga_t_dma.h b/MCUME_teensy41/teensycastaway/vga_t_dma.h deleted file mode 100644 index b14d9d3..0000000 --- a/MCUME_teensy41/teensycastaway/vga_t_dma.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - Wrapping class to extend VGA_T4 to TFT_T_DMA -*/ - -#ifndef _VGA_T_DMAH_ -#define _VGA_T_DMAH_ - -#ifdef __cplusplus -#include -#endif - - -#define RGBVAL16(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) - - - - -#ifdef HIRES -#define TFT_WIDTH 640 -#define TFT_REALWIDTH 640 -#else -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 -#endif - -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - - -#ifdef __cplusplus - -class TFT_T_DMA: public VGA_T4 -{ - public: - // Fake touch screen functions - bool isTouching(void) { return false; } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { } - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { }; - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { } - - // fake DMA functions - void startDMA(void) { }; - void stopDMA(void) { }; - - // fake no DMA functions - void writeScreenNoDma(const vga_pixel *pcolors) { writeScreen(pcolors); } - void fillScreenNoDma(vga_pixel color) { clear(color); } - void drawTextNoDma(int16_t x, int16_t y, const char * text, vga_pixel fgcolor, vga_pixel bgcolor, bool doublesize) { drawText(x,y,text,fgcolor,bgcolor,doublesize); } - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, vga_pixel color) { drawRect(x, y, w, h, color); } - void drawSpriteNoDma(int16_t x, int16_t y, const int16_t *bitmap) { drawSprite(x, y, bitmap); } - void drawSpriteNoDma(int16_t x, int16_t y, const int16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh) { drawSprite(x, y, bitmap, croparx, cropary, croparw, croparh); } -}; - - -#endif -#endif diff --git a/MCUME_teensy41/teensycastaway/test.cpp b/MCUME_teensy41/teensycastaway/wrapemu.cpp similarity index 74% rename from MCUME_teensy41/teensycastaway/test.cpp rename to MCUME_teensy41/teensycastaway/wrapemu.cpp index 9f169ec..7345c69 100644 --- a/MCUME_teensy41/teensycastaway/test.cpp +++ b/MCUME_teensy41/teensycastaway/wrapemu.cpp @@ -9,9 +9,7 @@ #include "xram.h" #include "iopins.h" -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#endif + #ifndef NO_SOUND #include "sound.h" @@ -19,6 +17,8 @@ #include "tossw14.h" +static bool hires = true; + int8 *membase; int8 *rombase; @@ -39,30 +39,12 @@ extern unsigned char fdc_motor; #define XRES 320 #define YRES 200 -#ifdef HAS_T4_VGA -#define DOUBLE_BUFFERING 1 +static unsigned short line[XRES*2]; // max 640 pixels in hires -#ifdef DOUBLE_BUFFERING -#ifdef HIRES -static vga_pixel line[XRES*2]; -#else -static vga_pixel line[XRES]; -#endif -#else -#ifdef HIRES -static unsigned short line[XRES*2]; -#else -static unsigned short line[XRES]; -#endif -#endif -#else -static unsigned short line[XRES]; -#endif #define PALMULT8(x) ((x)<<5) #define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) -#ifndef DOUBLE_BUFFERING void Redraw16 ( int row, int vid_adr ) { static unsigned short palmap [ 16 ]; @@ -91,12 +73,13 @@ void Redraw16 ( int row, int vid_adr ) *line_o++ = palmap [ ind ]; } } -#ifdef HIRES - emu_DrawLine16(&line[0], XRES, YRES*2, row*2); - emu_DrawLine16(&line[0], XRES, YRES*2, row*2+1); -#else - emu_DrawLine16(&line[0], XRES, YRES, row); -#endif + if (hires) { + emu_DrawLine16(&line[0], XRES, YRES*2, row*2); + emu_DrawLine16(&line[0], XRES, YRES*2, row*2+1); + } + else { + emu_DrawLine16(&line[0], XRES, YRES, row); + } } void Redraw16_med ( int row, int vid_adr ) @@ -122,60 +105,63 @@ void Redraw16_med ( int row, int vid_adr ) for (bit=15;bit>=0;bit--) { int ind = (pl0 >> bit) & 0x1; ind += ((pl1 >> bit) & 0x1)<<1; -#ifdef HIRES - *line_o++ = palmap [ ind ]; -#else - if (bit & 0x01) + if (hires) { *line_o++ = palmap [ ind ]; -#endif + } + else { + if (bit & 0x01) + *line_o++ = palmap [ ind ]; + } } } -#ifdef HIRES - emu_DrawLine16(&line[0], XRES*2, YRES*2, row*2); - emu_DrawLine16(&line[0], XRES*2, YRES*2, row*2+1); -#else - emu_DrawLine16(&line[0], XRES, YRES, row); -#endif + if (hires) { + emu_DrawLine16(&line[0], XRES*2, YRES*2, row*2); + emu_DrawLine16(&line[0], XRES*2, YRES*2, row*2+1); + } + else { + emu_DrawLine16(&line[0], XRES, YRES, row); + } } void Redraw16_hi ( int row, int vid_adr ) { -#ifdef HIRES + if (hires) { static unsigned short palmap [ 2 ]; - register unsigned short *line_i; - line_i = (unsigned short *)(&membase[vid_adr]); - register unsigned short *line_o= &line[0]; - if (vid_flag) { - palmap [ 0 ] = RGBVAL16(0xff,0xff,0xff); - palmap [ 1 ] = RGBVAL16(0x00,0x00,0x00); - vid_flag=0; - } - register int col; - register int bit; - for (col=0; col<40; col++) { - register unsigned short pl0=*line_i++; - for (bit=15;bit>=0;bit--) { - int ind = (pl0 >> bit) & 0x1; - *line_o++ = palmap [ ind ]; + register unsigned short *line_i; + line_i = (unsigned short *)(&membase[vid_adr]); + register unsigned short *line_o= &line[0]; + if (vid_flag) { + palmap [ 0 ] = RGBVAL16(0xff,0xff,0xff); + palmap [ 1 ] = RGBVAL16(0x00,0x00,0x00); + vid_flag=0; } - } - emu_DrawLine16(&line[0], XRES*2, YRES*2, row*2); - line_o= &line[0]; - for (col=0; col<40; col++) { - register unsigned short pl0=*line_i++; - for (bit=15;bit>=0;bit--) { - int ind = (pl0 >> bit) & 0x1; - *line_o++ = palmap [ ind ]; + register int col; + register int bit; + for (col=0; col<40; col++) { + register unsigned short pl0=*line_i++; + for (bit=15;bit>=0;bit--) { + int ind = (pl0 >> bit) & 0x1; + *line_o++ = palmap [ ind ]; + } } + emu_DrawLine16(&line[0], XRES*2, YRES*2, row*2); + line_o= &line[0]; + for (col=0; col<40; col++) { + register unsigned short pl0=*line_i++; + for (bit=15;bit>=0;bit--) { + int ind = (pl0 >> bit) & 0x1; + *line_o++ = palmap [ ind ]; + } + } + emu_DrawLine16(&line[0], XRES*2, YRES*2, row*2+1); } - emu_DrawLine16(&line[0], XRES*2, YRES*2, row*2+1); -#endif } -#endif void ast_Init(void) { + hires = emu_IsVgaHires()?true:false; + emu_printf("Allocating RAM"); membase = (int8*)xram_MemPool(); @@ -418,9 +404,9 @@ static void do_events(void) if (bClick & MASK_KEY_USER2) { if (isMouse) isMouse = false; else isMouse = true; -#ifndef HAS_T4_VGA +//#ifndef HAS_T4_VGA emu_setKeymap(0); -#endif +//#endif } @@ -457,18 +443,18 @@ static void do_events(void) int mouseEvent = emu_GetMouse(&dx,&dy,&buts); if (mouseEvent){ mouse_x += dx; -#ifdef HIRES - if (vid_shiftmode==COL2) { - if ( mouse_x >= XRES*2 ) { - mouse_x = XRES*2-1; - } + if ( (vid_shiftmode==COL2) && (hires) ) { + if ( mouse_x >= XRES*2 ) { + mouse_x = XRES*2-1; + } } - else -#endif - if ( mouse_x >= XRES ) { - mouse_x = XRES-1; - } - else if ( mouse_x < 0 ) { + else { + if ( mouse_x >= XRES ) { + mouse_x = XRES-1; + } + } + + if ( mouse_x < 0 ) { mouse_x = 0; } mouse_y += dy; @@ -496,12 +482,12 @@ static void do_events(void) if (!isMouse) { int j = 0; - if (( k & MASK_JOY1_RIGHT) || ( k & MASK_JOY2_RIGHT)) { - j |= 0x08; - } if (( k & MASK_JOY1_LEFT) || ( k & MASK_JOY2_LEFT)) { j |= 0x04; } + if (( k & MASK_JOY1_RIGHT) || ( k & MASK_JOY2_RIGHT)) { + j |= 0x08; + } if (( k & MASK_JOY1_UP) || ( k & MASK_JOY2_UP)) { j |= 0x01; } @@ -519,17 +505,16 @@ static void do_events(void) else { if (( k & MASK_JOY1_RIGHT) || ( k & MASK_JOY2_RIGHT)) { mouse_x += 1; -#ifdef HIRES - if (vid_shiftmode==COL2) { - if ( mouse_x >= XRES*2 ) { - mouse_x = XRES*2-1; - } + if ( (vid_shiftmode==COL2) && (hires) ) { + if ( mouse_x >= XRES*2 ) { + mouse_x = XRES*2-1; + } + } + else { + if ( mouse_x >= XRES ) { + mouse_x = XRES-1; + } } - else -#endif - if ( mouse_x >= XRES ) { - mouse_x = XRES-1; - } } else if (( k & MASK_JOY1_LEFT) || ( k & MASK_JOY2_LEFT)) { mouse_x -= 1; @@ -598,149 +583,6 @@ static void do_events(void) } } -#ifdef DOUBLE_BUFFERING -static unsigned short lines[200*80]; -#ifdef HAS_T4_VGA -static unsigned char palettes[200*16]; -#else -static unsigned short palettes[200*16]; -#endif -static unsigned char modes[200]; - -static void renderScreen(void) { - register int col; - register int bit; - int row; - for (row=0; row<200; row++) { - int mode= modes[row]; - unsigned short * line_i = &lines[80*row]; -#ifdef HAS_T4_VGA - vga_pixel * palmap = &palettes[row*16]; - register vga_pixel *line_o= (unsigned char *)&line[0]; -#else - unsigned short * palmap = &palettes[row*16]; - register unsigned short *line_o= &line[0]; -#endif - if (mode==MONO) { -#ifdef HIRES - for (col=0; col<40; col++) { - register unsigned short pl0=*line_i++; - for (bit=15;bit>=0;bit--) { - int ind = (pl0 >> bit) & 0x1; - *line_o++ = palmap [ ind ]; - } - } - emu_DrawLine8((vga_pixel*)&line[0], XRES*2, YRES*2, row*2); - line_o= (vga_pixel *)&line[0]; - for (col=0; col<40; col++) { - register unsigned short pl0=*line_i++; - for (bit=15;bit>=0;bit--) { - int ind = (pl0 >> bit) & 0x1; - *line_o++ = palmap [ ind ]; - } - } - emu_DrawLine8((unsigned char*)&line[0], XRES*2, YRES*2, row*2+1); -#endif - } - else if (mode==COL2) { - for (col=0; col<40; col++) { - register unsigned short pl0=*line_i++,pl1=*line_i++; - for (bit=15;bit>=0;bit--) { - int ind = (pl0 >> bit) & 0x1; - ind += ((pl1 >> bit) & 0x1)<<1; -#ifdef HIRES - *line_o++ = palmap [ ind ]; -#else - if (bit & 0x01) - *line_o++ = palmap [ ind ]; -#endif - } - } -#ifdef HAS_T4_VGA -#ifdef HIRES - emu_DrawLine8((unsigned char*)&line[0], XRES*2, YRES*2, row*2); - emu_CopyLine(XRES*2, YRES*2, row*2, row*2+1); -#else - emu_DrawLine8((unsigned char*)&line[0], XRES, YRES, row); -#endif -#else - emu_DrawLine16(&line[0], XRES, YRES, row); -#endif - } - else { // COL4 - for (col=0; col<20; col++) { - register unsigned short pl0=*line_i++,pl1=*line_i++,pl2=*line_i++,pl3=*line_i++; - for (bit=15;bit>=0;bit--) { - int ind = (pl0 >> bit) & 0x1; - ind += ((pl1 >> bit) & 0x1)<<1; - ind += ((pl2 >> bit) & 0x1)<<2; - ind += ((pl3 >> bit) & 0x1)<<3; - *line_o++ = palmap [ ind ]; - } - } -#ifdef HAS_T4_VGA -#ifdef HIRES - emu_DrawLine8((unsigned char*)&line[0], XRES, YRES*2, row*2); - emu_CopyLine(XRES*2, YRES*2, row*2, row*2+1); -#else - emu_DrawLine8((unsigned char*)&line[0], XRES, YRES, row); -#endif -#else - emu_DrawLine16(&line[0], XRES, YRES, row); -#endif - } - } -} - - -static copyLine(int row, int vid_adr, int mode) -{ -#ifdef HAS_T4_VGA - vga_pixel * palmap=&palettes[row*16]; -#else - unsigned short * palmap=&palettes[row*16]; -#endif - unsigned char i, r, g, b; - modes[row] = mode; - if (vid_flag) { - vid_flag=0; - } - if (mode==MONO) { - #ifdef HAS_T4_VGA - palmap [ 0 ] = VGA_RGB(0xff,0xff,0xff); - palmap [ 1 ] = VGA_RGB(0x00,0x00,0x00); - #else - palmap [ 0 ] = RGBVAL16(0xff,0xff,0xff); - palmap [ 1 ] = RGBVAL16(0x00,0x00,0x00); - #endif - } - else if (mode==COL2) { - for (i = 0; i < 4; i++) { - b = PALMULT8 ( (vid_col[i] & 0x7) ); - g = PALMULT8 ( ((vid_col[i] >> 4) & 0x7) ); - r = PALMULT8 ( ((vid_col[i] >> 8) & 0x7) ); - #ifdef HAS_T4_VGA - palmap [ i ] = VGA_RGB(r,g,b); - #else - palmap [ i ] = RGBVAL16(r,g,b); - #endif - } - } - else { - for (i = 0; i < 16; i++) { - b = PALMULT8 ( (vid_col[i] & 0x7) ); - g = PALMULT8 ( ((vid_col[i] >> 4) & 0x7) ); - r = PALMULT8 ( ((vid_col[i] >> 8) & 0x7) ); - #ifdef HAS_T4_VGA - palmap [ i ] = VGA_RGB(r,g,b); - #else - palmap [ i ] = RGBVAL16(r,g,b); - #endif - } - } - memcpy(&lines[row*80], &membase[vid_adr], 160); -} -#endif void ast_Step(void) @@ -874,10 +716,6 @@ void ast_Step(void) if (emu_FrameSkip() == 0 ) { //Update video address and draw screen line vid_adr=(vid_baseh<<16)+(vid_basem<<8)+(hbl-64)*160; -#ifdef DOUBLE_BUFFERING - copyLine(hbl - 64, vid_adr,vid_shiftmode); -#else - if (vid_shiftmode==MONO) { Redraw16_hi( hbl - 64, vid_adr ); } @@ -885,8 +723,7 @@ void ast_Step(void) Redraw16_med( hbl - 64, vid_adr ); } else { Redraw16( hbl - 64, vid_adr ); - } -#endif + } } //Timer-A event count mode @@ -915,22 +752,7 @@ void ast_Step(void) //Vertical blank? else if (hbl>=313) { -#ifdef DOUBLE_BUFFERING - if (vid_shiftmode==MONO) { - emu_DrawWaitLine(440); - emu_tweakVideo(1,0,0); - } - else if (vid_shiftmode==COL2) { - emu_DrawWaitLine(440); - emu_tweakVideo(1,0,0); - } else { - emu_DrawWaitLine(440); - emu_tweakVideo(0,0,0); - } - renderScreen(); -#else emu_DrawVsync(); -#endif do_events(); #ifndef NO_SOUND Sound_Update_VBL(); diff --git a/MCUME_teensy41/teensycastaway/test.h b/MCUME_teensy41/teensycastaway/wrapemu.h similarity index 69% rename from MCUME_teensy41/teensycastaway/test.h rename to MCUME_teensy41/teensycastaway/wrapemu.h index cbb8a07..274469e 100644 --- a/MCUME_teensy41/teensycastaway/test.h +++ b/MCUME_teensy41/teensycastaway/wrapemu.h @@ -1,4 +1,10 @@ +#ifdef __cplusplus +extern "C" { +#endif extern void ast_Init(void); extern void ast_Step(void); extern void ast_Start(char * floppy1, char * floppy2, int mode); extern void ast_Input(int click); +#ifdef __cplusplus +} +#endif diff --git a/MCUME_teensy41/teensycolem/emuapi.cpp b/MCUME_teensy41/teensycolem/emuapi.cpp index 0e98162..e128cca 100644 --- a/MCUME_teensy41/teensycolem/emuapi.cpp +++ b/MCUME_teensy41/teensycolem/emuapi.cpp @@ -5,25 +5,31 @@ extern "C" { #include "iopins.h" } -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#else -#include "tft_t_dma.h" -#endif +#include -#ifdef HAS_USBKEY +#ifdef HAS_USB #include "USBHost_t36.h" // Read this header first for key info USBHost myusb; USBHub hub1(myusb); +#ifdef HAS_USBKEY KeyboardController keyboard1(myusb); USBHIDParser hid1(myusb); MouseController mouse1(myusb); +#endif +#ifdef HAS_USBMIDI MIDIDevice midi1(myusb); #endif +#ifdef HAS_USBJOY +#define COUNT_JOYSTICKS 4 +JoystickController joysticks[COUNT_JOYSTICKS](myusb); +#endif +#endif static bool emu_writeConfig(void); static bool emu_readConfig(void); static bool emu_eraseConfig(void); +static bool emu_writeGfxConfig(char * display_type); +static int emu_readGfxConfig(void); static bool mouseDetected = false; static bool keyboardDetected = false; @@ -34,6 +40,7 @@ static File file; #define MAX_FILES 64 #define AUTORUN_FILENAME "autorun.txt" +#define GFX_CFG_FILENAME "gfxmode.txt" #define MAX_FILENAME_SIZE 34 #define MAX_MENULINES 9 @@ -53,7 +60,8 @@ static File file; #define MENU_VGA_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) #define MENU_VGA_YOFFSET (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37) -extern TFT_T_DMA tft; +#include "t4_dsp.h" +T4_DSP tft; static int nbFiles=0; static int curFile=0; @@ -65,6 +73,8 @@ static char selected_filename[MAX_FILENAME_SIZE]=""; static char second_selected_filename[MAX_FILENAME_SIZE]=""; static bool menuRedraw=true; static bool autorun=false; +static bool vgahires=false; + static const unsigned short * keys; #ifdef TEECOMPUTER @@ -158,6 +168,29 @@ void emu_Free(void * pt) free(pt); } +#define SMEMPOOL (0x800000) +EXTMEM static unsigned char slowmem[SMEMPOOL]; +static int slowmempt = 0; + +void * emu_SMalloc(unsigned int size) +{ + void * mem = (void*)&slowmem[slowmempt]; + slowmempt += size; + + if ( slowmempt > SMEMPOOL ) { + mem = NULL; + emu_printf("failure to allocate slow"); + } + else { + emu_printf("could allocate slow static "); + emu_printf(size); + } + return mem; +} + +void emu_SFree(void * pt) +{ +} /******************************** * Input and keyboard ********************************/ @@ -329,6 +362,12 @@ int emu_ReadKeys(void) #endif if ( row & 0x02 ) retval |= MASK_JOY2_BTN; + +#ifdef EXTPAD + if ( sh_pressed ) retval |= MASK_KEY_USER3; + if ( fn_pressed ) retval |= MASK_KEY_USER1; + digitalWrite(KLED, 0); +#else // Handle LED flash uint32_t time_ms=millis(); if ((time_ms-last_t_ms) > 100) { @@ -412,8 +451,9 @@ int emu_ReadKeys(void) if ( key_fn ) retval |= MASK_KEY_USER2; if ( ( key_fn ) && (keymatrix[4] == 0x10 )) retval |= MASK_KEY_USER1; +#endif - if ( (key_fn) && (key_sh) ) + if ( (fn_pressed) && (sh_pressed) ) #else if ( ((retval & (MASK_KEY_USER1+MASK_KEY_USER2)) == (MASK_KEY_USER1+MASK_KEY_USER2)) || (retval & MASK_KEY_USER4 ) ) @@ -453,8 +493,10 @@ int emu_ReadKeys(void) while (true) { ; } -#endif +#endif } + + emu_GetJoystick(); return (retval); } @@ -607,7 +649,7 @@ int emu_setKeymap(int index) { } int emu_GetMouse(int *x, int *y, int *buts) { -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBKEY) if (mouse1.available()) { *buts = mouse1.getButtons(); *x = mouse1.getMouseX(); @@ -620,7 +662,23 @@ int emu_GetMouse(int *x, int *y, int *buts) { return 0; } -#ifdef HAS_USBKEY +int emu_GetJoystick(void) { +#if defined(HAS_USB) && (HAS_USBJOY) + for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) { + if (joysticks[joystick_index].available()) { + uint64_t axis_mask = joysticks[joystick_index].axisMask(); + uint64_t axis_changed_mask = joysticks[joystick_index].axisChangedMask(); + uint32_t buttons = joysticks[joystick_index].getButtons(); + Serial.printf("Joystick(%d): buttons = %x", joystick_index, buttons); + Serial.println(); + } + } + return 1; +#endif + return 0; +} + +#if defined(HAS_USB) && (HAS_USBKEY) void OnPress(auto key) { keyboardDetected = true; @@ -764,7 +822,7 @@ int emu_KeyboardDetected(void) { return (keyboardDetected?1:0); } -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) static unsigned char midiBuffer[16]; static unsigned char midiLastCmd=0; static int midiDataCnt=0; @@ -772,8 +830,7 @@ static int midiCmdNbParam=0; #endif void emu_MidiOnDataReceived(unsigned char value) { - -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) //Serial.println(value, HEX); //10000000 = 128 = note off //10010000 = 144 = note on @@ -941,6 +998,7 @@ void emu_MidiOnDataReceived(unsigned char value) { /******************************** * Menu file loader UI ********************************/ +#ifdef FILEBROWSER static int readNbFiles(void) { int totalFiles = 0; @@ -970,8 +1028,6 @@ static int readNbFiles(void) { return totalFiles; } - - void backgroundMenu(void) { menuRedraw=true; tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00)); @@ -981,11 +1037,13 @@ void backgroundMenu(void) { int handleMenu(uint16_t bClick) { if (autorun) { + toggleMenu(false); + menuRedraw=false; return (ACTION_RUN1); } int action = ACTION_NONE; - if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) ) { + if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) || ( bClick & MASK_KEY_USER2 ) ) { char newpath[MAX_FILENAME_PATH]; strcpy(newpath, selection); strcat(newpath, "/"); @@ -996,17 +1054,31 @@ int handleMenu(uint16_t bClick) File file = SD.open(selection); if (file.isDirectory()) { curFile = 0; - nbFiles = readNbFiles(); + nbFiles = readNbFiles(); + menuRedraw=true; } - else { - action = ACTION_RUN1; + else + { #ifdef TEECOMPUTER - if (key_extmode) { + if ( (key_extmode) || ( key_sh) ) { emu_writeConfig(); } + if ( tft.getMode() < MODE_VGA_320x240) { + if ( bClick & MASK_KEY_USER2 ) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + } + //emu_SwapJoysticks(0); #endif + toggleMenu(false); + menuRedraw=false; + return (ACTION_RUN1); } - menuRedraw=true; } else if ( bClick & MASK_KEY_USER1 ) { menuRedraw=true; @@ -1015,19 +1087,14 @@ int handleMenu(uint16_t bClick) strcat(second_selection, "/"); strcat(second_selection, second_selected_filename); action = ACTION_RUN2; - } - else if ( bClick & MASK_KEY_USER2 ) { - menuRedraw=true; - //action = ACTION_RUN3; - emu_SwapJoysticks(0); - } + } else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) { if (curFile!=0) { menuRedraw=true; curFile--; } } - else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { + else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { if ((curFile-9)>=0) { menuRedraw=true; curFile -= 9; @@ -1042,7 +1109,7 @@ int handleMenu(uint16_t bClick) menuRedraw=true; } } - else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { + else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { if ((curFile<(nbFiles-9)) && (nbFiles)) { curFile += 9; menuRedraw=true; @@ -1099,12 +1166,12 @@ int handleMenu(uint16_t bClick) return (action); } -bool menuActive(void) +int menuActive(void) { - return (menuOn); + return (menuOn?1:0); } -void toggleMenu(bool on) { +void toggleMenu(int on) { if (on) { menuOn=true; backgroundMenu(); @@ -1122,7 +1189,7 @@ char * menuSecondSelection(void) { return (second_selection); } - +#endif /******************************** * OSKB handling @@ -1140,8 +1207,9 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) char c[4] = {' ',0,' ',0}; const char * cpt = str; int i=0; - int fb_width,fb_height; - tft.get_frame_buffer_size(&fb_width, &fb_height); + int fb_width,fb_height,fbstride; + + fbstride = tft.get_frame_buffer_size(&fb_width, &fb_height); int ypos = (bottom?(fb_height-2*8):0); int line = row + (bottom?2:0); while ((c[1] = *cpt++)) @@ -1150,7 +1218,7 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0); else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff); if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff); - tft.drawTextNoDma(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); + tft.drawText(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); i++; } } @@ -1248,7 +1316,7 @@ int handleOSKB(void) { return retval; } -void toggleOSKB(bool forceon) { +void toggleOSKB(int forceon) { if (forceon) { oskbOn = true; drawOSKB(); @@ -1332,6 +1400,17 @@ int emu_FileRead(void * buf, int size, int handler) #endif } +int emu_FileWrite(void * buf, int size, int handler) +{ +// emu_printf("emu_FileWrite"); +// emu_printi(handler); +#ifdef HCFH + return (file.write(buf, size)); +#else + return (getFileHandler(handler).write(buf, size)); +#endif +} + int emu_FileGetc(int handler) { // emu_printf("FileGetc"); // emu_printi(handler); @@ -1404,6 +1483,9 @@ unsigned int emu_FileSize(const char * filepath) emu_printf(filesize); lofile.close(); } + else { + emu_printf("filesize failed"); + } return(filesize); } @@ -1489,6 +1571,48 @@ static bool emu_eraseConfig(void) SD.remove (ROMSDIR "/" AUTORUN_FILENAME); } +static bool emu_writeGfxConfig(char * display_type) +{ + bool retval = false; + SD.remove ("/" GFX_CFG_FILENAME); + if (strcmp(display_type, "VGA")) { + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(display_type, strlen(display_type)) != strlen(display_type)) { + emu_printf("GFX config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + } + return retval; +} + +#define CFG_VGA 0 +#define CFG_ILI 1 +#define CFG_ST 2 + +static int emu_readGfxConfig(void) +{ + int retval = CFG_VGA; // No file = VGA + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + if (filesize == 2) // "ST" + { + retval = CFG_ST; + } + else if (filesize == 3) // "ILI" + { + retval = CFG_ILI; + } + lofile.close(); + } + return retval; +} + /******************************** * File IO compatibility ********************************/ @@ -1670,62 +1794,249 @@ FRESULT f_mkdir (const char* path) /******************************** - * Initialization + * GFX wrapper ********************************/ -void emu_init(void) +static unsigned short palette16[PALETTE_SIZE]; +static IntervalTimer myTimer; +volatile boolean vbl=true; +volatile boolean vgatimervsync=false; +static void (*vblCallback)(void) = nullptr; +static int skip=0; + +static void vblCount() { + if (vbl) { + vbl = false; + } else { + vbl = true; + } +} + +void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) +{ + if (index= MODE_VGA_320x240 ) { + if (vgatimervsync) { + while (vbl==vb) {}; + } + else { + tft.waitSync(); + } + } + else { + while (vbl==vb) {}; + } + if (vblCallback != nullptr) { + vblCallback(); + } +} + +void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride) +{ + if (skip == 0) { + tft.writeScreenPal(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); + } +} +void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLinePal(width,height,line, VBuf, palette16); + } +} + +void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine(width,height,line, VBuf); + } +} + +void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine8(width,height,line, VBuf, palette16); + } +} + +int emu_IsVga(void) +{ + return (tft.getMode() >= MODE_VGA_320x240?1:0); +} + +int emu_IsVgaHires(void) +{ + return (tft.getMode() >= MODE_VGA_640x240?1:0); +} + +int emu_FrameSkip(void) +{ + return skip; +} + + +/******************************** + * AUDIO wrapper +********************************/ +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +AudioPlaySystem mymixer; + +void emu_sndInit() { + Serial.println("sound init"); + mymixer.begin_audio(256, mymixer.snd_Mixer); + mymixer.start(); +} + +void emu_sndPlaySound(int chan, int volume, int freq) +{ + if (chan < 6) { + mymixer.sound(chan, freq, volume); + } + /* + Serial.print(chan); + Serial.print(":" ); + Serial.print(volume); + Serial.print(":" ); + Serial.println(freq); + */ +} + +void emu_sndPlayBuzz(int size, int val) { + mymixer.buzz(size,val); + //Serial.print((val==1)?1:0); + //Serial.print(":"); + //Serial.println(size); +} +#endif + +/******************************** + * Initialization +********************************/ +void emu_init(int hires) { Serial.begin(115200); + vgahires = hires; -#ifdef HAS_USBKEY +#ifdef HAS_USB myusb.begin(); +#ifdef HAS_USBKEY keyboard1.attachPress(OnPress); keyboard1.attachRelease(OnRelease); #endif +#endif - while (!SD.begin(SD_CS)) +#ifdef FILEBROWSER + if (!SD.begin(SD_CS)) { - Serial.println("SD begin failed, retrying..."); - delay(1000); + Serial.println("No SD card detected"); } strcpy(selection,ROMSDIR); - FileHandlersInit(); - nbFiles = readNbFiles(); - - Serial.print("SD initialized, files found: "); Serial.println(nbFiles); +#endif emu_InitJoysticks(); #ifdef SWAP_JOYSTICK - joySwapped = true; + joySwapped = true; #else - joySwapped = false; + joySwapped = false; #endif -#ifdef TEECOMPUTER -#ifndef HAS_T4_VGA - tft.flipscreen(false); -#endif -#endif int keypressed = emu_ReadKeys(); +#ifdef HAS_T4_VGA + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } +#else + int gfx_mode = CFG_VGA; // default +#ifdef FILEBROWSER + gfx_mode = emu_readGfxConfig(); +#endif + // Force VGA if UP pressed + if (keypressed & MASK_JOY2_UP) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("VGA"); +#endif + gfx_mode = CFG_VGA; + } + else { + if (keypressed & MASK_JOY2_LEFT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ST"); +#endif + gfx_mode = CFG_ST; + } + else if (keypressed & MASK_JOY2_RIGHT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ILI"); +#endif + gfx_mode = CFG_ILI; + } + } + if (gfx_mode == CFG_VGA) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + else + { + tft.begin(gfx_mode == CFG_ILI?MODE_TFTILI_320x240:MODE_TFTST_320x240); + } +#endif + if (keypressed & MASK_JOY2_DOWN) { tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) ); tft.drawTextNoDma(64,48, (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); +#ifdef FILEBROWSER emu_eraseConfig(); delay(1000); +#endif } else { +#ifdef FILEBROWSER if (emu_readConfig()) { autorun = true; } +#endif } +#ifdef FILEBROWSER toggleMenu(true); +#endif } -void emu_start(void) +void emu_start(int vblms, void * callback, int forcetimervsync) { + vgatimervsync = forcetimervsync?true:false; + tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); + tft.startRefresh(); + if (callback != nullptr) { + vblCallback = callback; + } + + myTimer.begin(vblCount, vblms); +#ifdef HAS_SND + emu_sndInit(); +#endif usbnavpad = 0; } diff --git a/MCUME_teensy41/teensycolem/emuapi.h b/MCUME_teensy41/teensycolem/emuapi.h index 87bf480..5dd6130 100644 --- a/MCUME_teensy41/teensycolem/emuapi.h +++ b/MCUME_teensy41/teensycolem/emuapi.h @@ -2,124 +2,14 @@ #define EMUAPI_H #include "platform_config.h" - -//#define TIMER_REND 1 -#define EXTRA_HEAP 0x10 - -// Title: < > -#define TITLE " Coleco Emulator" -#define ROMSDIR "coleco" - -#define emu_Init(ROM) {coc_Init();coc_Start(ROM);} -#define emu_Step() {coc_Step();} -#define emu_Input(x) {coc_Input(x);} - -#define MAX_FILENAME_PATH 64 -#define NB_FILE_HANDLER 4 -#define PALETTE_SIZE 16 -#define VID_FRAME_SKIP 0x0 -#define TFT_VBUFFER_YCROP 0 -#define SINGLELINE_RENDERING 1 - -#define R32(rgb) ((rgb>>16)&0xff) -#define G32(rgb) ((rgb>>8)&0xff) -#define B32(rgb) (rgb & 0xff) +#include "emucfg.h" #define ACTION_NONE 0 -#define ACTION_MAXKBDVAL 16 -#define ACTION_EXITKBD 128 -#define ACTION_RUN1 129 -#define ACTION_RUN2 130 -#define ACTION_RUN3 131 - -#ifdef KEYMAP_PRESENT - -#define keylables_map0_0 (char *)"qwertyuiop\x1a" -#define keylables_map0_1 (char *)" asdfghjkl\x19" -#define keylables_map0_2 (char *)" zxcvbnm,.;/" -#define keylables_map0_3 (char *)" +\x10-" -const unsigned short key_map0[] = { - 'q','w','e','r','t','y','u','i','o','p',157, //lowecase - 0,'a','s','d','f','g','h','j','k','l',0x0D, - 0,'z','x','c','v','b','n','m',',','.',';','/', - 145,157,29,17, - 0,'+',' ','-' - }; - -#define keylables_map1_0 (char *)"QWERTYUIOP@" -#define keylables_map1_1 (char *)" ASDFGHJKL\x19" -#define keylables_map1_2 (char *)" ZXCVBNM<>:?" -#define keylables_map1_3 (char *)" =\x10_" -const unsigned short key_map1[] = { - 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase - 0,'A','S','D','F','G','H','J','K','L',0x0D, - 0,'Z','X','C','V','B','N','M','<','>',':','?', - 145,157,29,17, - 0,'=',' ','_' - }; - -#define keylables_map2_0 (char *)"!\"#$%^&*()@" -#define keylables_map2_1 (char *)" |\\[]{} " -#define keylables_map2_2 (char *)" <>:?" -#define keylables_map2_3 (char *)" =\x10_" -const unsigned short key_map2[] = { - '!','"','#','$','%','^','&','*','(',')','@', // shiftothers - 0, '|','\\','[',']','{','}','\'',0,0,0, - 0, 0,0,0,0,0,0,0,'<','>',':','?', - 0,0,0,0, - 0,'=',' ','_' - }; - -#define keylables_map3_0 (char *)"1234567890 " -#define keylables_map3_1 (char *)" " -#define keylables_map3_2 (char *)" " -#define keylables_map3_3 (char *)" " - -const unsigned short key_map3[] = { - '1','2','3','4','5','6','7','8','9','0',0, // digit keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map4_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " -#define keylables_map4_1 (char *)" " -#define keylables_map4_2 (char *)" " -#define keylables_map4_3 (char *)" " - -const unsigned short key_map4[] = { - 133,134,135,136,137,138,139,140,0,0,0, // function keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map5_0 (char *)" " -#define keylables_map5_1 (char *)" " -#define keylables_map5_2 (char *)" " -#define keylables_map5_3 (char *)" " - -const unsigned short key_map5[] = { - 0,0,0,0,0,0,0,0,0,0,0, // extra keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -const unsigned short matkeys[] = { - 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 - 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 - 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 - 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN - 0x510,0x010,0x110,0x310, // row 4 - }; - -#endif - +#define ACTION_RUN1 1 +#define ACTION_RUN2 2 +#define FORCE_VGATIMERVSYNC 1 +#define SUPPORT_HIRES 1 #define MASK_JOY2_RIGHT 0x0001 #define MASK_JOY2_LEFT 0x0002 @@ -136,24 +26,25 @@ const unsigned short matkeys[] = { #define MASK_JOY1_BTN 0x1000 #define MASK_KEY_USER4 0x2000 +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) #ifdef __cplusplus extern "C" { -#else -#define bool unsigned char +extern void emu_init(int hires=0); +extern void emu_start(int vblms, void * callback, int forcetimervsync=0); #endif - -extern void emu_init(void); -extern void emu_start(void); extern void emu_printf(const char * text); extern void emu_printi(int val); extern void emu_printh(int val); extern void * emu_Malloc(unsigned int size); extern void * emu_MallocI(unsigned int size); extern void emu_Free(void * pt); +extern void * emu_SMalloc(unsigned int size); +extern void emu_SFree(void * pt); extern int emu_FileOpen(const char * filepath, const char * mode); extern int emu_FileRead(void * buf, int size, int handler); +extern int emu_FileWrite(void * buf, int size, int handler); extern int emu_FileGetc(int handler); extern int emu_FileSeek(int handler, int seek, int origin); extern int emu_FileTell(int handler); @@ -164,24 +55,23 @@ extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size); extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek); extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index); -extern void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride); -extern void emu_DrawLine(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line); extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line); +extern void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride); extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line); -extern void emu_CopyLine(int width, int height, int ysrc, int ydst); extern void emu_DrawVsync(void); extern int emu_FrameSkip(void); -extern void * emu_LineBuffer(int line); -extern void emu_tweakVideo(int shiftdelta, int numdelta, int denomdelta); +extern int emu_IsVga(void); +extern int emu_IsVgaHires(void); -extern bool menuActive(void); +extern int menuActive(void); extern char * menuSelection(void); extern char * menuSecondSelection(void); -extern void toggleMenu(bool on); +extern void toggleMenu(int on); extern int handleMenu(unsigned short bClick); extern int handleOSKB(void); -extern void toggleOSKB(bool forceon); +extern void toggleOSKB(int forceon); extern void emu_InitJoysticks(void); extern int emu_SwapJoysticks(int statusOnly); @@ -190,6 +80,7 @@ extern int emu_ReadKeys(void); extern int emu_GetPad(void); extern int emu_GetMouse(int *x, int *y, int *buts); extern int emu_MouseDetected(void); +extern int emu_GetJoystick(void); extern int emu_KeyboardDetected(void); extern int emu_ReadAnalogJoyX(int min, int max); extern int emu_ReadAnalogJoyY(int min, int max); diff --git a/MCUME_teensy41/teensycolem/emucfg.h b/MCUME_teensy41/teensycolem/emucfg.h new file mode 100644 index 0000000..08df254 --- /dev/null +++ b/MCUME_teensy41/teensycolem/emucfg.h @@ -0,0 +1,115 @@ +#ifndef EMUCFG_H +#define EMUCFG_H + +#include "wrapemu.h" + +// Title: < > +#define TITLE " Coleco Emulator" +#define ROMSDIR "coleco" + +#define emu_Init(ROM) {coc_Init();coc_Start(ROM);} +#define emu_Step() {coc_Step();} +#define emu_Input(x) {coc_Input(x);} + +#define MAX_FILENAME_PATH 64 +#define NB_FILE_HANDLER 4 + +#define PALETTE_SIZE 16 +#define VID_FRAME_SKIP 0x0 +#define TFT_VBUFFER_YCROP 0 +#define SINGLELINE_RENDERING 1 +//#define CUSTOM_SND 1 +//#define TIMER_REND 1 +//#define EXTPAD 1 +#define EXTRA_HEAP 0x10 +#define FILEBROWSER 1 + + +#ifdef KEYMAP_PRESENT + +#define keylables_map0_0 (char *)"1234567890 " +#define keylables_map0_1 (char *)" " +#define keylables_map0_2 (char *)" " +#define keylables_map0_3 (char *)" " +const unsigned short key_map0[] = { + 'q','w','e','r','t','y','u','i','o','p',0, + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,0,0 + }; + +#define keylables_map1_0 (char *)"1234567890 " +#define keylables_map1_1 (char *)" " +#define keylables_map1_2 (char *)" " +#define keylables_map1_3 (char *)" " +const unsigned short key_map1[] = { + 0,0,'#',0,0,0,0,'*',0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,0,0 + }; + +#define keylables_map2_0 (char *)" # * " +#define keylables_map2_1 (char *)" " +#define keylables_map2_2 (char *)" " +#define keylables_map2_3 (char *)" " +const unsigned short key_map2[] = { + '1','2','3','4','5','6','7','8','9','0',0, + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,0,0 + }; + +#define keylables_map3_0 (char *)" " +#define keylables_map3_1 (char *)" " +#define keylables_map3_2 (char *)" " +#define keylables_map3_3 (char *)" " + +const unsigned short key_map3[] = { + 0,0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,0,0 + }; + +#define keylables_map4_0 (char *)" " +#define keylables_map4_1 (char *)" " +#define keylables_map4_2 (char *)" " +#define keylables_map4_3 (char *)" " + +const unsigned short key_map4[] = { + 0,0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map5_0 (char *)" " +#define keylables_map5_1 (char *)" " +#define keylables_map5_2 (char *)" " +#define keylables_map5_3 (char *)" " + +const unsigned short key_map5[] = { + 0,0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,0,0 + }; + +const unsigned short matkeys[] = { + 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 + 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 + 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 + 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN + 0x510,0x010,0x110,0x310, // row 4 + }; + +#endif + +#endif diff --git a/MCUME_teensy41/teensycolem/platform_config.h b/MCUME_teensy41/teensycolem/platform_config.h index cad8176..66aa365 100644 --- a/MCUME_teensy41/teensycolem/platform_config.h +++ b/MCUME_teensy41/teensycolem/platform_config.h @@ -4,13 +4,13 @@ #define TEECOMPUTER 1 #ifdef TEECOMPUTER -//#define ILI9341 1 -//#define ST7789 1 -//#define TFTSPI1 1 -#define HAS_T4_VGA 1 +#define TFTSPI1 1 +//#define HAS_T4_VGA 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 -#define INVX 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 #define PT8211 1 #else @@ -19,7 +19,11 @@ #define INVX 1 #define INVY 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 +#define PT8211 1 #endif diff --git a/MCUME_teensy41/teensycolem/t4_dsp.cpp b/MCUME_teensy41/teensycolem/t4_dsp.cpp new file mode 100644 index 0000000..43301fa --- /dev/null +++ b/MCUME_teensy41/teensycolem/t4_dsp.cpp @@ -0,0 +1,1774 @@ +/* + TFT/VGA driver + DMA TFT driver based on C64 ILI9341 dma driver from Frank Bösing, 2017 +*/ + +#include "T4_DSP.h" + +#include +#include + +#include "font8x8.h" + +// TFT constants and variables +#define TFT_LINEARINT 1 +#define LINEARINT_HACK 1 +#define DMA_LINES_PER_BLOCK 64 +#define DMA_NUM_SETTINGS 4 + +#define TFT_SWRESET 0x01 +#define TFT_SLPOUT 0x11 +#define TFT_INVON 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_MADCTL 0x36 +#define TFT_PIXFMT 0x3A +#define TFT_MADCTL_MY 0x80 +#define TFT_MADCTL_MX 0x40 +#define TFT_MADCTL_MV 0x20 +#define TFT_MADCTL_ML 0x10 +#define TFT_MADCTL_RGB 0x00 +#define TFT_MADCTL_BGR 0x08 +#define TFT_MADCTL_MH 0x04 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) +//#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) +//#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) +//#define R16(rgb) ((rgb>>8)&0xf8) +//#define G16(rgb) ((rgb>>3)&0xfc) +//#define B16(rgb) ((rgb<<3)&0xf8) + +// LPSPI4 = SPI0 in Teensy 4.0 +// LPSPI3 = SPI1 in Teensy 4.0 +// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) + +#ifdef TFTSPI1 +#define SPI SPI1 +#define LPSPIP_TDR LPSPI3_TDR +#define LPSPIP_CR LPSPI3_CR +#define LPSPIP_CFGR1 LPSPI3_CFGR1 +#define LPSPIP_TCR LPSPI3_TCR +#define LPSPIP_DER LPSPI3_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX +#else +#define LPSPIP_TDR LPSPI4_TDR +#define LPSPIP_CR LPSPI4_CR +#define LPSPIP_CFGR1 LPSPI4_CFGR1 +#define LPSPIP_TCR LPSPI4_TCR +#define LPSPIP_DER LPSPI4_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX +#endif + +#define SPICLOCK 60000000 +#define SPI_MODE SPI_MODE0 + +// VGA constants and macros +typedef uint8_t vga_pixel; +#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) + +static DMASetting dmasettings[DMA_NUM_SETTINGS]; +static DMAChannel dmatx; +static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K +static volatile uint8_t rstop = 0; +static volatile bool cancelled = false; +static volatile uint8_t curTransfer = 0; +static uint8_t nbTransfer = 0; +static uint16_t * tft_buffer; +static int tft_width; +static int tft_height; +static int tft_stride; + +#define DELAY_MASK 0x80 +PROGMEM static const uint8_t init_commands[] = { + 1+DELAY_MASK, TFT_SWRESET, 150, + 1+DELAY_MASK, TFT_SLPOUT, 255, + 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, + 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, + 1, TFT_INVON, + 1, TFT_DISPON, + 0 +}; + +// VGA constants and variables +// Objective: +// generates VGA signal fully in hardware with as little as possible CPU help + +// Principle: +// QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) +// 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate +// RGB out, combined to create 8bits(/12bits) output. + +// Note: +// - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels +// - experimental resolution: 352x240,352x480 +// - experimental resolution: 512x240,512x480 (not stable) +// - video memory is allocated using malloc in T4 heap +// - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing +// but tried to be compensated by pixel shifting +// - Default is 8bits RRRGGGBB (332) +// But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! +// - Only ok at 600MHz else some disturbances visible + + + +#define TOP_BORDER 40 +#define PIN_HBLANK 15 + +#define PIN_R_B2 33 +#define PIN_R_B1 4 +#define PIN_R_B0 3 +#define PIN_G_B2 2 +#define PIN_G_B1 13 +#define PIN_G_B0 11 +#define PIN_B_B1 12 +#define PIN_B_B0 10 + + +#define DMA_HACK 0x80 + +#define R16(rgb) ((rgb>>8)&0xf8) +#define G16(rgb) ((rgb>>3)&0xfc) +#define B16(rgb) ((rgb<<3)&0xf8) + +// VGA 640x480@60Hz +// Screen refresh rate 60 Hz +// Vertical refresh 31.46875 kHz +// Pixel freq. 25.175 MHz +// +// Visible area 640 25.422045680238 us +// Front porch 16 0.63555114200596 us +// Sync pulse 96 3.8133068520357 us +// Back porch 48 1.9066534260179 us +// Whole line 800 31.777557100298 us + +#define frame_freq 60.0 // Hz +#define line_freq 31.46875 // KHz +#define pix_freq (line_freq*800) // KHz (25.175 MHz) + +// pix_period = 39.7ns +// H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) +#define frontporch_pix 20 //16 +#define backporch_pix 44 //48 + +// Flexio Clock +// PLL3 SW CLOCK (3) => 480 MHz +// PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) +#define FLEXIO_CLK_SEL_PLL3 3 +#define FLEXIO_CLK_SEL_PLL5 2 + +/* Set video PLL */ +// There are /1, /2, /4, /8, /16 post dividers for the Video PLL. +// The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, +// and CCM_ANALOG_MISC2 register sets according to the following equation. +// PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + +// nfact: +// This field controls the PLL loop divider. +// Valid range for DIV_SELECT divider value: 27~54. + +#define POST_DIV_SELECT 2 + +// Full buffer including back/front porch +static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; +static uint32_t dstbuffer __attribute__((aligned(32))); + +// Visible vuffer +static vga_pixel * vga_buffer; +static int vga_width; +static int vga_height; +static int vga_stride; + +static int maxpixperline; +static int left_border; +static int right_border; +static int line_double; +static int pix_shift; +static int ref_div_select; +static int ref_freq_num; +static int ref_freq_denom; +static int ref_pix_shift; +static int combine_shiftreg; + +#ifdef DEBUG +static uint32_t ISRTicks_prev = 0; +volatile uint32_t ISRTicks = 0; +#endif + +uint8_t T4_DSP::_rst; +uint8_t T4_DSP::_cs; +uint8_t T4_DSP::_dc; +uint8_t T4_DSP::_mosi; +uint8_t T4_DSP::_sclk; +uint8_t T4_DSP::_vsync_pin = -1; +DMAChannel T4_DSP::flexio1DMA; +DMAChannel T4_DSP::flexio2DMA; + +static volatile uint32_t VSYNC = 0; +static volatile uint32_t currentLine=0; +#define NOP asm volatile("nop\n\t"); +static gfx_mode_t gfxmode = MODE_UNDEFINED; + + +FASTRUN void T4_DSP::TFT_isr(void) { + dmatx.clearInterrupt(); + curTransfer++; + if (curTransfer >= nbTransfer) { + curTransfer = 0; + if (cancelled) { + dmatx.disable(); + rstop = 1; + } + } + arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); +} + +FASTRUN void T4_DSP::QT3_isr(void) { + TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); + TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); + + cli(); + + // V-PULSE + if (currentLine > 0) { + digitalWrite(_vsync_pin, 1); + VSYNC = 0; + } else { + digitalWrite(_vsync_pin, 0); + VSYNC = 1; + } + + currentLine++; + currentLine = currentLine % 525; + + + uint32_t y = (currentLine - TOP_BORDER) >> line_double; + // Visible area + + if (y >= 0 && y < vga_height) { + // Disable DMAs + //DMA_CERQ = flexio2DMA.channel; + //DMA_CERQ = flexio1DMA.channel; + + // Setup source adress + // Aligned 32 bits copy + unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; + flexio2DMA.TCD->SADDR = p; + if (pix_shift & DMA_HACK) + { + // Unaligned copy + uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; + flexio1DMA.TCD->SADDR = p2; + } + else { + p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 + flexio1DMA.TCD->SADDR = p; + } + + // Enable DMAs + //flexio2DMA.enable(); + //flexio1DMA.enable(); + DMA_SERQ = flexio2DMA.channel; + DMA_SERQ = flexio1DMA.channel; + arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); + } + sei(); + +#ifdef DEBUG + ISRTicks++; +#endif + asm volatile("dsb"); +} + +static void setDmaStruct() { + uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; + uint16_t * fb = (uint16_t*)malloc(remaining); + tft_buffer = fb; + tft_width = TFT_WIDTH; + tft_height = TFT_HEIGHT; + tft_stride = TFT_WIDTH; + uint16_t col=RGBVAL16(0x00,0x00,0x00); + int i=0; + while (remaining > 0) { + int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); + blocks[i] = fb; + for (int j=0;jATTR_DST = 1; + dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); + dmasettings[i].interruptAtCompletion(); + fb += len/2; + remaining -= len; + i++; + } + dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); + nbTransfer = i; +} + +static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 +{ +//if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; + CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE + | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 + | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); + CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; + CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock + const int div_post_pll = 1; // other values: 2,4 + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass +} + +T4_DSP::T4_DSP() +{ + _cs = TFT_CS; + _dc = TFT_DC; + _rst = TFT_RST; + _mosi = TFT_MOSI; + _sclk = TFT_SCLK; + pinMode(_dc, OUTPUT); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, 1); + digitalWrite(_dc, 1); + _vsync_pin = 8; +} + + +void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { + int dx=0; + int dy=0; + digitalWrite(_dc, 0); + SPI.transfer(TFT_CASET); + digitalWrite(_dc, 1); + SPI.transfer16(x1+dx); + digitalWrite(_dc, 1); + SPI.transfer16(x2+dx); + digitalWrite(_dc, 0); + SPI.transfer(TFT_PASET); + digitalWrite(_dc, 1); + SPI.transfer16(y1+dy); + digitalWrite(_dc, 1); + SPI.transfer16(y2+dy); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + return; +} + +void T4_DSP::tft_setup(bool isST) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + // RESET if reset pin defined + if (_rst != 0xff) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + const uint8_t *addr = init_commands; + uint8_t count; + digitalWrite(_cs, 0); + while (count = *addr++) { + uint8_t command = *addr++; + if ( (command == TFT_INVON) && (!isST) ) { + // Skip TFT_INVON for ILI + } + else { + digitalWrite(_dc, 0); // command + SPI.transfer(command); + uint16_t ms = count & DELAY_MASK; + count &= ~DELAY_MASK; + while (--count > 0) { // data + uint8_t data = *addr++; + if ( (command == TFT_MADCTL) && (isST) ) { + data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; + } + digitalWrite(_dc, 1); + SPI.transfer(data); + } + if (ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + digitalWrite(_cs, 1); + SPI.endTransaction(); + delay(2); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + } + } + } + digitalWrite(_cs, 1); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + SPI.endTransaction(); + /* + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_dc, 0); + digitalWrite(_cs, 0); + SPI.transfer(TFT_MADCTL); + digitalWrite(_dc, 1); + SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); + // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); + digitalWrite(_cs, 1); + SPI.endTransaction(); + */ + cancelled = false; +} + +// display VGA image +gfx_error_t T4_DSP::begin(gfx_mode_t mode) +{ + uint32_t flexio_clock_div; + combine_shiftreg = 0; +// int div_select = 49; +// int num = 135; +// int denom = 100; + int div_select = 20; + int num = 9800; + int denom = 10000; + int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; + int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; + set_videoClock(div_select,num,denom,true); + +#ifdef DEBUG + Serial.println(mode); + Serial.println("mode"); +#endif + + switch(mode) + { + case MODE_TFTILI_320x240: +#ifdef DEBUG + Serial.println("TFTILI_320x240"); +#endif + tft_setup(false); + gfxmode = mode; + break; + case MODE_TFTST_320x240: +#ifdef DEBUG + Serial.println("TFTST_320x240"); +#endif + tft_setup(true); + gfxmode = mode; + break; + + case MODE_VGA_320x240: +#ifdef DEBUG + Serial.println("VGA_320x240"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_320x480: +#ifdef DEBUG + Serial.println("VGA_320x480"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_640x240: +#ifdef DEBUG + Serial.println("VGA_640x240"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/pix_freq; + line_double = 1; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_640x480: +#ifdef DEBUG + Serial.println("VGA_640x480"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = (flexio_freq/pix_freq); + line_double = 0; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_512x240: +#ifdef DEBUG + Serial.println("VGA_512x240"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 1; + pix_shift = 0; + break; + + case MODE_VGA_512x480: +#ifdef DEBUG + Serial.println("VGA_512x480"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 0; + pix_shift = 0; + break; + + case MODE_VGA_352x240: +#ifdef DEBUG + Serial.println("VGA_352x240"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_352x480: +#ifdef DEBUG + Serial.println("VGA_352x480"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + } + + if (mode >= MODE_VGA_320x240) + { + if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { + fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); + digitalWrite(_cs, 0); + digitalWrite(_dc, 0); + SPI.transfer(TFT_DISPOFF); + digitalWrite(_cs, 1); + delay(20); + digitalWrite(_cs, 0); + digitalWrite(_cs, 1); + } + gfxmode = mode; + + maxpixperline = vga_stride; + // Save param for tweek adjustment + ref_div_select = div_select; + ref_freq_num = num; + ref_freq_denom = denom; + ref_pix_shift = pix_shift; + +#ifdef DEBUG + Serial.println("frequency"); + Serial.println(flexio_freq); + Serial.println("div"); + Serial.println(flexio_freq/pix_freq); +#endif + + pinMode(_vsync_pin, OUTPUT); + pinMode(PIN_HBLANK, OUTPUT); + + /* Basic pin setup FlexIO1 */ + pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 + pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 + pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 + pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 + /* Basic pin setup FlexIO2 */ + pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 + pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 + pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 + pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 + + /* High speed and drive strength configuration */ + *(portControlRegister(PIN_G_B2)) = 0xFF; + *(portControlRegister(PIN_R_B0)) = 0xFF; + *(portControlRegister(PIN_R_B1)) = 0xFF; + *(portControlRegister(PIN_R_B2)) = 0xFF; + *(portControlRegister(PIN_B_B0)) = 0xFF; + *(portControlRegister(PIN_B_B1)) = 0xFF; + *(portControlRegister(PIN_G_B0)) = 0xFF; + *(portControlRegister(PIN_G_B1)) = 0xFF; + + /* Set clock for FlexIO1 and FlexIO2 */ + CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) + | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); + CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) + | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); + + + /* Set up pin mux FlexIO1 */ + *(portConfigRegister(PIN_G_B2)) = 0x14; + *(portConfigRegister(PIN_R_B0)) = 0x14; + *(portConfigRegister(PIN_R_B1)) = 0x14; + *(portConfigRegister(PIN_R_B2)) = 0x14; + /* Set up pin mux FlexIO2 */ + *(portConfigRegister(PIN_B_B0)) = 0x14; + *(portConfigRegister(PIN_B_B1)) = 0x14; + *(portConfigRegister(PIN_G_B0)) = 0x14; + *(portConfigRegister(PIN_G_B1)) = 0x14; + + /* Enable the clock */ + CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + /* Enable the FlexIO with fast access */ + FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + + uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; + uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; + + /* Shifter 0 registers for FlexIO2 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 + inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter + stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled + startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable + timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 + timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock + pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output + pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity + shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode + /* Shifter 0 registers for FlexIO1 */ + FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + /* Shifter 0 registers for FlexIO1 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 + FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + if (combine_shiftreg) { + pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled + FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + } + /* Timer 0 registers for FlexIO2 */ + timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset + timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output + timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset + timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare + timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert + stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled + startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled + if (combine_shiftreg) { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag + } + else { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag + } + triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low + triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected + pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled + //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 + //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high + timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode + // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) + + int shifts_per_transfer; + if (combine_shiftreg) { + shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 + } + else { + shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 + } + FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); + /* Timer 0 registers for FlexIO1 */ + FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); +#ifdef DEBUG + Serial.println("FlexIO setup complete"); +#endif + + /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ + if (combine_shiftreg) { + FLEXIO2_SHIFTSDEN |= (1<<1); + FLEXIO1_SHIFTSDEN |= (1<<1); + } + else { + FLEXIO2_SHIFTSDEN |= (1<<0); + FLEXIO1_SHIFTSDEN |= (1<<0); + } + /* Disable DMA channel so it doesn't start transferring yet */ + flexio1DMA.disable(); + flexio2DMA.disable(); + /* Set up DMA channel to use Shifter 0 trigger */ + flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); + flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); + + + if (combine_shiftreg) { + flexio2DMA.TCD->NBYTES = 8; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 8; + flexio2DMA.TCD->CITER = maxpixperline / 8; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + flexio1DMA.TCD->NBYTES = 8; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 8; + flexio1DMA.TCD->CITER = maxpixperline / 8; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Setup DMA2 Flexio2 copy + flexio2DMA.TCD->NBYTES = 4; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 4; + flexio2DMA.TCD->CITER = maxpixperline / 4; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + // Setup DMA1 Flexio1 copy + // Use pixel shift to avoid color smearing? + if (pix_shift & DMA_HACK) + { + if (pix_shift & 0x3 == 0) { + // Aligned 32 bits copy (32bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Unaligned (source) 32 bits copy (8bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 1; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion + } + } + else + { + // Aligned 32 bits copy + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + } + +#ifdef DEBUG + Serial.println("DMA setup complete"); +#endif + + // enable clocks for QTIMER3: generates the 15KHz for hsync + // Pulse: + // low : 3.8133 us => 569x6.7ns + // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) + // (OLD TEST) + // (4us low, 28us high => 32us) + // (597x6.7ns for 4us) + // (4179x6.7ns for 28us) + CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 + //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 + + #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz + #define MARGIN_D 1000 + + TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer + // Invert output pin as we want the interupt on rising edge + TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) + TMR3_CNTR3 = 0; + TMR3_LOAD3 = 0; + + /* Inverted timings */ + unsigned long long cpu_freq = F_CPU; + unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; + int rate2 = rate; + + int substract = 1; + if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { + substract=5; + rate2=1652; + } + + #ifdef DEBUG + Serial.print("MARGIN_N is: "); + Serial.println(rate2, DEC); + Serial.print("SUBSTRACT is: "); + Serial.println(substract, DEC); +#endif + TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; + TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; + /* + TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; + */ + TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on + TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), + // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) + //configure Teensy pin Compare output + IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 + attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function + NVIC_ENABLE_IRQ(IRQ_QTIMER3); +#ifdef DEBUG + Serial.println("QTIMER3 setup complete"); + Serial.print("V-PIN is "); + Serial.println(_vsync_pin); +#endif + + /* initialize gfx buffer */ + if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift + if (gfxbuffer == NULL) return(GFX_ERROR); +#ifdef DEBUG + Serial.println("Memory allocated"); +#endif + + memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); + vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; +#ifdef DEBUG + Serial.println(vga_stride); + Serial.println(vga_height); + Serial.println("Screen cleared"); +#endif + } + + return(GFX_OK); +} + +gfx_mode_t T4_DSP::getMode(void) +{ + return gfxmode; +} + +void T4_DSP::startRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + curTransfer = 0; + rstop = 0; + //dmatx.begin(true); + dmatx.attachInterrupt(TFT_isr); + setDmaStruct(); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + + digitalWrite(_cs, HIGH); + SPI.begin(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + + LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: + LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX + LPSPIP_TCR = 15; // Framesize 16 Bits + //LPSPIP_FCR = 0; // Fifo Watermark + LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable + LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: + dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); + + dmatx = dmasettings[0]; + digitalWrite(_cs, 0); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + dmatx.enable(); + } +} + + +void T4_DSP::stopRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + rstop = 1; + unsigned long m = millis(); + cancelled = true; + while (!rstop) { + if ((millis() - m) > 100) break; + delay(10); + asm volatile("wfi"); + }; + rstop = 0; + delay(50); + cancelled = false; + dmatx.detachInterrupt(); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + SPI.end(); +#ifdef ST7789 +// begin(gfxmode); +#endif + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + } +} + +int T4_DSP::get_frame_buffer_size(int *width, int *height) { + if (gfxmode < MODE_VGA_320x240) { + if (width != nullptr) *width = tft_width; + if (height != nullptr) *height = tft_height; + return tft_stride; + } + else { + if (width != nullptr) *width = vga_width; + if (height != nullptr) *height = vga_height; + return vga_stride; + } +} + +void T4_DSP::waitSync() +{ + if (gfxmode >= MODE_VGA_320x240) { + while (VSYNC == 0) {}; + } +} + +void T4_DSP::waitLine(int line) +{ + if (gfxmode >= MODE_VGA_320x240) { + while (currentLine != line) {}; + } +} + +/*********************************************************************************************** + No DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreenNoDma(uint16_t color) { + if (gfxmode < MODE_VGA_320x240) { + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + int i,j; + for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(arx, ary, arx+arw-1, ary+arh-1); + bitmap = bitmap + bmp_offy*w + bmp_offx; + for (int row=0;row> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + bits = *charpt++; + //digitalWrite(_dc, 1); + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + x +=8; + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + else { + drawText(x, y, text, fgcolor, bgcolor, doublesize); + } +} + + +/*********************************************************************************************** + DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreen(uint16_t color) { + int i,j; + if (gfxmode < MODE_VGA_320x240) { + for (j=0; j> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + dst=&tft_buffer[l*tft_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + x +=8; + } + } + else { + vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); + vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); + vga_pixel * dst; + while ((c = *text++)) { + const unsigned char * charpt=&font8x8[c][0]; + int l=y; + for (int i=0;i<8;i++) + { + unsigned char bits; + if (doublesize) { + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + x +=8; + } + } +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { + drawSprite(x,y,bitmap, 0,0,0,0); +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) +{ + int bmp_offx = 0; + int bmp_offy = 0; + uint16_t *bmp_ptr; + int w =*bitmap++; + int h = *bitmap++; + if ( (arw == 0) || (arh == 0) ) { + // no crop window + arx = x; + ary = y; + arw = w; + arh = h; + } + else { + if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + int l=ary; + bitmap = bitmap + bmp_offy*w + bmp_offx; + + if (gfxmode < MODE_VGA_320x240) { + for (int row=0;row tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]; + pos +=step; + } + #endif + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i 2) ) y += (tft_height-height)/2; + uint16_t * dst=&tft_buffer[y*tft_stride]; + if (width > tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]]; + pos +=step; + } +#endif + } + else if ((width*2) == tft_width) { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]]; + *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i tft_width) { + int step = ((width << 8)/tft_width); + int pos = 0; + for (int i=0; i> 8]]; + pos +=step; + } + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = pix; + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i +#include +#endif + +#include "platform_config.h" +#include "iopins.h" + + + +#ifndef TFT_WIDTH +#define TFT_WIDTH 320 +#endif +#define TFT_REALWIDTH 320 + +#ifndef TFT_HEIGHT +#define TFT_HEIGHT 240 +#endif +#define TFT_REALHEIGHT 240 + + +typedef enum gfx_mode_t +{ + MODE_UNDEFINED = 0, + MODE_TFTILI_320x240 = 1, + MODE_TFTST_320x240 = 2, + MODE_VGA_320x240 = 3, + MODE_VGA_320x480 = 4, + MODE_VGA_352x240 = 5, + MODE_VGA_352x480 = 6, + MODE_VGA_512x240 = 7, + MODE_VGA_512x480 = 8, + MODE_VGA_640x240 = 9, + MODE_VGA_640x480 = 10 +} gfx_mode_t; + +typedef enum gfx_error_t +{ + GFX_OK = 0, + GFX_ERROR = -1 +} gfx_error_t; + + +#ifdef __cplusplus + +class T4_DSP +{ + public: + T4_DSP(); + + gfx_error_t begin(gfx_mode_t mode); + gfx_mode_t getMode(void); + void startRefresh(void); + void stopRefresh(); + + int get_frame_buffer_size(int *width, int *height); + void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); + + // wait next Vsync + void waitSync(); + void waitLine(int line); + + // NoDMA functions + void fillScreenNoDma(uint16_t color); + void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + // DMA functions + void fillScreen(uint16_t color); + void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + void writeLine(int width, int height, int y, uint16_t *buf); + void writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + void writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16); + void writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + + protected: + static uint8_t _rst, _cs, _dc; + static uint8_t _mosi, _sclk; + static uint8_t _vsync_pin; + static DMAChannel flexio1DMA; + static DMAChannel flexio2DMA; + void tft_setup(bool isST); + static void TFT_isr(void); + static void QT3_isr(void); +}; + +#endif +#endif diff --git a/MCUME_teensy41/teensycolem/teensycolem.ino b/MCUME_teensy41/teensycolem/teensycolem.ino index a228459..b60461b 100644 --- a/MCUME_teensy41/teensycolem/teensycolem.ino +++ b/MCUME_teensy41/teensycolem/teensycolem.ino @@ -3,136 +3,16 @@ extern "C" { #include "emuapi.h" } -extern "C" { -#include "Colem.h" -} - - -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -TFT_T_DMA tft; -#else -#include "tft_t_dma.h" -TFT_T_DMA tft = TFT_T_DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, TFT_TOUCH_CS, TFT_TOUCH_INT); -#endif - -bool vgaMode = false; - -static unsigned char palette8[PALETTE_SIZE]; -static unsigned short palette16[PALETTE_SIZE]; -static IntervalTimer myTimer; -volatile boolean vbl=true; -static int skip=0; -static elapsedMicros tius; - -static void vblCount() { - if (vbl) { - vbl = false; - } else { - vbl = true; - } -} - -void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) -{ - if (index>8, - 320 & 0xFF, // YEND = 320 - ST7735_INVON , DELAY, // 7: hack - 10, - ST7735_NORON , DELAY, // 8: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 9: Main screen turn on, no args, w/delay - 255 -#endif -}; - -static void dmaInterrupt() { - dmatx.clearInterrupt(); - curTransfer++; - if (curTransfer >= nbTransfer) { - curTransfer = 0; - if (cancelled) { - dmatx.disable(); - rstop = 1; - } - } - arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2); -} - -static void setDmaStruct() { - uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; - int i=0; - uint16_t col=RGBVAL16(0x00,0x00,0x00);; - while (remaining > 0) { - uint16_t * fb = blocks[i]; - int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining); -#ifdef TFT_DEBUG - Serial.println((unsigned long)blocks[i]); - Serial.println(remaining); -#endif - switch (i) { - case 0: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb0[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0x00); -#endif - break; - case 1: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb1[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0xff); -#endif - break; - case 2: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb2[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0x00,0xff); -#endif - break; - case 3: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb3[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0xff,0x00,0xff); -#endif - break; - } - blocks[i] = fb; - if (blocks[i] == 0) { - Serial.print("ILI9341 allocaltion failed for block "); - Serial.println(i); - delay(10000); - } - - for (int j=0;jATTR_DST = 1; - dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); - dmasettings[i].interruptAtCompletion(); - remaining -= len; - i++; - } - dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); - nbTransfer = i; -#ifdef TFT_DEBUG - Serial.println(nbTransfer); -#endif -} - - -TFT_T_DMA::TFT_T_DMA(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso, uint8_t touch_cs, uint8_t touch_irq) -{ - _cs = cs; - _dc = dc; - _rst = rst; - _mosi = mosi; - _sclk = sclk; - _miso = miso; - pinMode(_dc, OUTPUT); - pinMode(_cs, OUTPUT); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); - if ( (touch_cs != 255) && (touch_irq != 255) ) { - _touch_irq = touch_irq; - _touch_cs = touch_cs; - pinMode(_touch_cs, OUTPUT); - pinMode(touch_irq, INPUT_PULLUP); - digitalWrite(_touch_cs, 1); - } -} - - -void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { - int dx=0; - int dy=0; -#ifdef ST7789 - if (TFT_REALWIDTH == TFT_REALHEIGHT) - { -#ifdef ROTATE_SCREEN - if (!flipped) { - dy += 80; - } -#else - if (flipped) { - dx += 80; - } -#endif - } -#endif - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - SPI.transfer16(x1+dx); - digitalWrite(_dc, 1); - SPI.transfer16(x2+dx); - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - digitalWrite(_dc, 1); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - return; - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - - SPI.transfer16(x1+dx); - SPI.transfer16(x2+dx); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - -void TFT_T_DMA::begin(void) { - SPI.setMOSI(_mosi); - SPI.setMISO(_miso); - SPI.setSCK(_sclk); - SPI.begin(); - - // Initialize display - if (_rst != 0xff) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - const uint8_t *addr = init_commands; - digitalWrite(_cs, 0); -#ifdef ILI9341 - while (1) { - uint8_t count = *addr++; - if (count-- == 0) break; - - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - - while (count-- > 0) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - } - - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(ILI9341_DISPON); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); -#endif -#ifdef ST7789 - uint8_t numCommands, numArgs; - uint16_t ms; - numCommands = *addr++; // Number of commands to follow - while(numCommands--) { // For each command... - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - numArgs = *addr++; // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs > 1) { // For each argument... - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - numArgs--; - } - - if (numArgs) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - if(ms) { - ms = *addr++; // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - digitalWrite(_cs, 1); - SPI.endTransaction(); - delay(ms); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - } - } - digitalWrite(_cs, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - SPI.endTransaction(); - - cancelled = false; - -#ifdef FLIP_SCREEN - flipscreen(true); -#else - flipscreen(false); -#endif -#ifdef ST7789 - if (TFT_REALWIDTH != TFT_REALHEIGHT) - { - flipscreen(true); - } -#endif -}; - - - -void TFT_T_DMA::flipscreen(bool flip) -{ - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(TFT_MADCTL); - digitalWrite(_dc, 1); - if (flip) { - flipped=true; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB); -#endif -#endif - } - else { - flipped=false; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB); -#endif -#endif - } - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - -boolean TFT_T_DMA::isflipped(void) -{ - return(flipped); -} - - -#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) - - -void TFT_T_DMA::startDMA(void) { - curTransfer = 0; - rstop = 0; - //dmatx.begin(true); - dmatx.attachInterrupt(dmaInterrupt); - setDmaStruct(); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - - digitalWrite(_cs, HIGH); - SPI.begin(); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); - - - LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: - LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX - LPSPIP_TCR = 15; // Framesize 16 Bits - //LPSPIP_FCR = 0; // Fifo Watermark - LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable - LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: - dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); - - dmatx = dmasettings[0]; - digitalWrite(_cs, 0); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - dmatx.enable(); -} - - -void TFT_T_DMA::stopDMA(void) { - rstop = 0; - wait(); - delay(50); - cancelled = false; - dmatx.detachInterrupt(); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - SPI.end(); -#ifdef ST7789 - begin(); -#endif -#ifdef ILI9341 - SPI.begin(); - digitalWrite(_cs, 0); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - SPI.endTransaction(); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); -} - -void TFT_T_DMA::wait(void) { - rstop = 1; - unsigned long m = millis(); - cancelled = true; - while (!rstop) { - if ((millis() - m) > 100) break; - delay(10); - asm volatile("wfi"); - }; - rstop = 0; -} - -int TFT_T_DMA::get_frame_buffer_size(int *width, int *height){ - if (width != nullptr) *width = TFT_REALWIDTH; - if (height != nullptr) *height = TFT_REALHEIGHT; - return TFT_REALWIDTH; -} - - -/*********************************************************************************************** - Touch functions - ***********************************************************************************************/ -/* Code based on ... - * - * @file XPT2046.cpp - * @date 19.02.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the XPT2046 driver for Arduino. - */ - -#define ADC_MAX 0x0fff - -void TFT_T_DMA::enableTouchIrq() -{ - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 }; - SPI.transfer((void*)&buf[0],3); - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); -} - -//Default callibration for non flipped -#define TX_MIN 30 -#define TY_MIN 20 -#define TX_MAX 300 -#define TY_MAX 220 - -//Default callibration for flipped -#define TFX_MIN 20 -#define TFY_MIN 25 -#define TFX_MAX 288 -#define TFY_MAX 221 - -static uint16_t txMin; -static uint16_t tyMin; -static uint16_t txMax; -static uint16_t tyMax; - - -void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { - if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) { - txMin = xMin; - tyMin = yMin; - txMax = xMax; - tyMax = yMax; - } - else { - if (flipped) { - txMin = TFX_MIN; - tyMin = TFY_MIN; - txMax = TFX_MAX; - tyMax = TFY_MAX; - } - else { - txMin = TX_MIN; - tyMin = TY_MIN; - txMax = TX_MAX; - tyMax = TY_MAX; - } - } -} - - -void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - if ( TOUCH_ENABLED() ) { - uint16_t x = 0; - uint16_t y = 0; - uint16_t z1 = 0; - uint16_t z2 = 0; - uint8_t i = 0; - int16_t xraw=0, yraw=0; - - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - - for(; i < 15; i++) { - // SPI requirer 32bit aliment - uint8_t buf[12] = { - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00 - }; - SPI.transfer(&buf[0], &buf[0], 12); - y += (buf[1] << 8 | buf[2])>>3; - x += (buf[4] << 8 | buf[5])>>3; - z1 += (buf[7] << 8 | buf[8])>>3; - z2 += (buf[10] << 8 | buf[11])>>3; - } - enableTouchIrq(); - - if(i == 0) { - *oX = 0; - *oY = 0; - *oZ = 0; - } - else { - x /= i; - y /= i; - z1 /= i; - z2 /= i; - } - - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); - int z = z1 + ADC_MAX - z2; - if (flipped) { - xraw = x; - yraw = y; - } else { - xraw = ADC_MAX - x; - yraw = ADC_MAX - y; - } - xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1); - yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1); - - *oX = xraw; - *oY = yraw; - *oZ = z; - } - else - { - *oX = 0; - *oY = 0; - *oZ = 0; - } -} - -void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - readRaw(oX,oY,oZ); - // callibrate ... - if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin); - if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin); - //Serial.print(*oX); - //Serial.print(" "); - //Serial.println(*oY); -} - - -/*********************************************************************************************** - No DMA functions - ***********************************************************************************************/ -void TFT_T_DMA::fillScreenNoDma(uint16_t color) { - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - int i,j; - for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(arx, ary, arx+arw-1, ary+arh-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - bits = *charpt++; - //digitalWrite(_dc, 1); - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - x +=8; -#ifdef ILI9341 - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); -#endif - digitalWrite(_cs, 1); - SPI.endTransaction(); - } - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - - - -/*********************************************************************************************** - DMA functions - ***********************************************************************************************/ -uint16_t * TFT_T_DMA::getLineBuffer(int j) -{ - uint16_t * block=blocks[j>>6]; - return(&block[(j&0x3F)*TFT_REALWIDTH]); -} - -void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) { - uint8_t *buffer=buf; - uint8_t *src; - - int i,j,y=0; - if (width*2 <= TFT_REALWIDTH) { - for (j=0; j>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH]; - for (i=0; i>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x]; - for (i=0; i>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - block=blocks[l>>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt++; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - x +=8; - } -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { - drawSprite(x,y,bitmap, 0,0,0,0); -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) -{ - int bmp_offx = 0; - int bmp_offy = 0; - uint16_t *bmp_ptr; - - int w =*bitmap++; - int h = *bitmap++; - - - if ( (arw == 0) || (arh == 0) ) { - // no crop window - arx = x; - ary = y; - arw = w; - arh = h; - } - else { - if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - int l=ary; - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx]; - bmp_ptr = (uint16_t*)bitmap; - for (int col=0;col -#include -#include -#endif - -#include "tft_t_dma_config.h" - -#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) -#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define R16(rgb) ((rgb>>8)&0xf8) -#define G16(rgb) ((rgb>>3)&0xfc) -#define B16(rgb) ((rgb<<3)&0xf8) - -#define PAL_COLOR_MASK 0xff - -#ifdef LOHRES -#define TFT_WIDTH 240 -#define TFT_REALWIDTH 240 -#else -#define TFT_WIDTH 256 -#define TFT_REALWIDTH 320 -#endif -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - -//#define WIDTH 272 -//#define HEIGHT 228 - -#define LINES_PER_BLOCK 64 -#define NR_OF_BLOCK 4 -#define SCREEN_DMA_NUM_SETTINGS NR_OF_BLOCK - - -#ifdef ILI9341 - -#define ILI9341_NOP 0x00 -#define ILI9341_SWRESET 0x01 -#define ILI9341_RDDID 0x04 -#define ILI9341_RDDST 0x09 - -#define ILI9341_SLPIN 0x10 -#define ILI9341_SLPOUT 0x11 -#define ILI9341_PTLON 0x12 -#define ILI9341_NORON 0x13 - -#define ILI9341_RDMODE 0x0A -#define ILI9341_RDMADCTL 0x0B -#define ILI9341_RDPIXFMT 0x0C -#define ILI9341_RDIMGFMT 0x0D -#define ILI9341_RDSELFDIAG 0x0F - -#define ILI9341_INVOFF 0x20 -#define ILI9341_INVON 0x21 -#define ILI9341_GAMMASET 0x26 -#define ILI9341_DISPOFF 0x28 -#define ILI9341_DISPON 0x29 - -#define ILI9341_CASET 0x2A -#define ILI9341_PASET 0x2B -#define ILI9341_RAMWR 0x2C -#define ILI9341_RAMRD 0x2E - -#define ILI9341_PTLAR 0x30 -#define ILI9341_MADCTL 0x36 -#define ILI9341_VSCRSADD 0x37 -#define ILI9341_PIXFMT 0x3A - -#define ILI9341_FRMCTR1 0xB1 -#define ILI9341_FRMCTR2 0xB2 -#define ILI9341_FRMCTR3 0xB3 -#define ILI9341_INVCTR 0xB4 -#define ILI9341_DFUNCTR 0xB6 - -#define ILI9341_PWCTR1 0xC0 -#define ILI9341_PWCTR2 0xC1 -#define ILI9341_PWCTR3 0xC2 -#define ILI9341_PWCTR4 0xC3 -#define ILI9341_PWCTR5 0xC4 -#define ILI9341_VMCTR1 0xC5 -#define ILI9341_VMCTR2 0xC7 - -#define ILI9341_RDID1 0xDA -#define ILI9341_RDID2 0xDB -#define ILI9341_RDID3 0xDC -#define ILI9341_RDID4 0xDD - -#define ILI9341_GMCTRP1 0xE0 -#define ILI9341_GMCTRN1 0xE1 - -#define ILI9341_MADCTL_MY 0x80 -#define ILI9341_MADCTL_MX 0x40 -#define ILI9341_MADCTL_MV 0x20 -#define ILI9341_MADCTL_ML 0x10 -#define ILI9341_MADCTL_RGB 0x00 -#define ILI9341_MADCTL_BGR 0x08 -#define ILI9341_MADCTL_MH 0x04 - -#define TFT_CASET ILI9341_CASET -#define TFT_PASET ILI9341_PASET -#define TFT_RAMWR ILI9341_RAMWR -#define TFT_MADCTL ILI9341_MADCTL - -#endif - - -#ifdef ST7789 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_RGB 0x00 -#define ST77XX_MADCTL_BGR 0x08 -#define ST77XX_MADCTL_MH 0x04 - -#define TFT_CASET ST7735_CASET -#define TFT_PASET ST7735_RASET -#define TFT_RAMWR ST7735_RAMWR -#define TFT_MADCTL ST7735_MADCTL - -#endif - - - -#ifdef __cplusplus - -class TFT_T_DMA -{ - public: - TFT_T_DMA(uint8_t _CS, uint8_t _DC, uint8_t _RST = 255, uint8_t _MOSI=11, uint8_t _SCLK=13, uint8_t _MISO=12, uint8_t touch_cs=38, uint8_t touch_irq=37); - - void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); - void begin(void); - void flipscreen(bool flip); - boolean isflipped(void); - void startDMA(void); - void stopDMA(); - int get_frame_buffer_size(int *width, int *height); - - // Touch screen functions - #define TOUCH_ENABLED() ((_touch_cs != 255) && (_touch_irq != 255)) - bool isTouching(void) { return ((!TOUCH_ENABLED())?false:(digitalRead(_touch_irq) == LOW)); } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax); - - // NoDMA functions - void writeScreenNoDma(const uint16_t *pcolors); - void fillScreenNoDma(uint16_t color); - void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - // DMA functions - uint16_t * getLineBuffer(int j); - void writeScreen(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int y, uint16_t *buf); - void fillScreen(uint16_t color); - void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - protected: - uint8_t _rst, _cs, _dc; - uint8_t _miso, _mosi, _sclk; - uint8_t _touch_irq=255, _touch_cs=255; - bool flipped=false; - - void wait(void); - void enableTouchIrq(); -}; - -#endif -#endif diff --git a/MCUME_teensy41/teensycolem/tft_t_dma_config.h b/MCUME_teensy41/teensycolem/tft_t_dma_config.h deleted file mode 100644 index 0a712da..0000000 --- a/MCUME_teensy41/teensycolem/tft_t_dma_config.h +++ /dev/null @@ -1,13 +0,0 @@ -#include "platform_config.h" - -//#define ST7789 1 -//#define ILI9341 1 - -#define TFT_LINEARINT 1 -#define LINEARINT_HACK 1 - -//#define FLIP_SCREEN 1 -//#define TFT_DEBUG 1 -#if defined(__IMXRT1052__) || defined(__IMXRT1062__) -//#define TFT_STATICFB 1 -#endif diff --git a/MCUME_teensy41/teensycolem/vga_t_dma.h b/MCUME_teensy41/teensycolem/vga_t_dma.h deleted file mode 100644 index 81a986b..0000000 --- a/MCUME_teensy41/teensycolem/vga_t_dma.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - Wrapping class to extend VGA_T4 to TFT_T_DMA -*/ - -#ifndef _VGA_T_DMAH_ -#define _VGA_T_DMAH_ - -#ifdef __cplusplus -#include -#endif - - -#define RGBVAL16(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) - - - - -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 - -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - - - -#ifdef __cplusplus - -class TFT_T_DMA: public VGA_T4 -{ - public: - // Fake touch screen functions - bool isTouching(void) { return false; } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { } - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { }; - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { } - - // fake DMA functions - void startDMA(void) { }; - void stopDMA(void) { }; - - // fake no DMA functions - void writeScreenNoDma(const vga_pixel *pcolors) { writeScreen(pcolors); } - void fillScreenNoDma(vga_pixel color) { clear(color); } - void drawTextNoDma(int16_t x, int16_t y, const char * text, vga_pixel fgcolor, vga_pixel bgcolor, bool doublesize) { drawText(x,y,text,fgcolor,bgcolor,doublesize); } - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, vga_pixel color) { drawRect(x, y, w, h, color); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap) { drawSprite(x, y, bitmap); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh) { drawSprite(x, y, bitmap, croparx, cropary, croparw, croparh); } -}; - - -#endif -#endif diff --git a/MCUME_teensy41/teensycolem/Colem.c b/MCUME_teensy41/teensycolem/wrapemu.c similarity index 95% rename from MCUME_teensy41/teensycolem/Colem.c rename to MCUME_teensy41/teensycolem/wrapemu.c index 898946b..8fdf023 100644 --- a/MCUME_teensy41/teensycolem/Colem.c +++ b/MCUME_teensy41/teensycolem/wrapemu.c @@ -158,7 +158,7 @@ void coc_Init(void) } -int coc_Start(char * Cartridge) +void coc_Start(char * Cartridge) { int *T,I,J; char *P; @@ -246,14 +246,12 @@ int coc_Start(char * Cartridge) ResetZ80(&ccpu); /* Reset Z80 registers */ if(Verbose) emu_printf("RUNNING ROM CODE...\n"); - return(1); } void coc_Step(void) { - //emu_printf("s"); RunZ80(&ccpu); - RunZ80(&ccpu); + emu_DrawVsync(); } void coc_Stop(void) @@ -341,37 +339,50 @@ void Joysticks(void) case '0': hk = 1; break; + case '#': + hk = 11; + //emu_printf("#"); + break; + case '*': + //emu_printf("*"); + hk = 12; + break; default: hk = 0; break; }; - if(hk) - JS[N]=(JS[N]&0xFFF0)|(hk-1); - - if (k & MASK_JOY2_BTN) - { - JS[N]&=0xBFFF; //Fire 1 + if(hk) { + JS[N]=(JS[N]&0xFFF0)|(hk-1); } - if (k & MASK_KEY_USER1) - { - JS[N]&=0xFFBF; //Fire 2 + else { + JS[N]=(JS[N]&0xFFF0); + if ( (k & MASK_JOY2_BTN) || (k & MASK_JOY1_BTN) ) + { + JS[N]&=0xBFFF; //Fire 1 + } + if (k & MASK_KEY_USER1) + { + JS[N]&=0xFFBF; //Fire 2 + } + if (k & MASK_KEY_USER2) + { + JS[0]=(JS[0]&0xFFF0)|(2); //1 + } + // JS[0]=(JS[0]&0xFFF0)|(12); + // JS[0]=(JS[0]&0xFFF0)|(13); + + if ( (k & MASK_JOY2_DOWN) || (k & MASK_JOY1_DOWN) ) + JS[N]&=0xFBFF; //Down + if ( (k & MASK_JOY2_UP) || (k & MASK_JOY1_UP) ) + JS[N]&=0xFEFF; //Up + if ( (k & MASK_JOY2_LEFT) || (k & MASK_JOY1_LEFT) ) + JS[N]&=0xF7FF; //Left + if ( (k & MASK_JOY2_RIGHT) || (k & MASK_JOY1_RIGHT) ) + JS[N]&=0xFDFF; //Right + + } - if (k & MASK_KEY_USER2) - { - JS[0]=(JS[0]&0xFFF0)|(2); //1 - } - // JS[0]=(JS[0]&0xFFF0)|(12); - // JS[0]=(JS[0]&0xFFF0)|(13); - - if (k & MASK_JOY2_DOWN) - JS[N]&=0xFBFF; //Down - if (k & MASK_JOY2_UP) - JS[N]&=0xFEFF; //Up - if (k & MASK_JOY2_RIGHT) - JS[N]&=0xF7FF; //Right - if (k & MASK_JOY2_LEFT) - JS[N]&=0xFDFF; //Left JoyState[0]=JS[0];JoyState[1]=JS[1]; } @@ -504,7 +515,7 @@ word LoopZ80(Z80 *R, int * ras) if(!UCount) { (SCR[ScrMode].Refresh)(CurLine); #if SINGLELINE_RENDERING - emu_DrawLine(XBuf, WIDTH, HEIGHT, CurLine); + emu_DrawLinePal16(XBuf, WIDTH, HEIGHT, CurLine); #else #endif } @@ -701,9 +712,8 @@ void RefreshScreen(void) { #if SINGLELINE_RENDERING #else - emu_DrawScreen(XBuf, WIDTH, HEIGHT, WIDTH); -#endif - emu_DrawVsync(); + emu_DrawScreenPal16(XBuf, WIDTH, HEIGHT, WIDTH); +#endif } /** RefreshBorder() ******************************************/ diff --git a/MCUME_teensy41/teensycolem/Colem.h b/MCUME_teensy41/teensycolem/wrapemu.h similarity index 69% rename from MCUME_teensy41/teensycolem/Colem.h rename to MCUME_teensy41/teensycolem/wrapemu.h index 35c935b..d705e07 100644 --- a/MCUME_teensy41/teensycolem/Colem.h +++ b/MCUME_teensy41/teensycolem/wrapemu.h @@ -1,5 +1,11 @@ +#ifdef __cplusplus +extern "C" { +#endif extern void coc_Init(void); extern void coc_Start(char * CartName); extern void coc_Step(void); extern void coc_Stop(void); extern void coc_Input(int click); +#ifdef __cplusplus +} +#endif diff --git a/MCUME_teensy41/teensydoom/emuapi.cpp b/MCUME_teensy41/teensydoom/emuapi.cpp index c367cb0..89c964d 100644 --- a/MCUME_teensy41/teensydoom/emuapi.cpp +++ b/MCUME_teensy41/teensydoom/emuapi.cpp @@ -1705,7 +1705,7 @@ void emu_init(void) #ifdef TEECOMPUTER #ifndef HAS_T4_VGA - tft.flipscreen(false); + tft.flipscreen(true); #endif #endif int keypressed = emu_ReadKeys(); diff --git a/MCUME_teensy41/teensydoom/platform_config.h b/MCUME_teensy41/teensydoom/platform_config.h index f3eb85c..86e0b15 100644 --- a/MCUME_teensy41/teensydoom/platform_config.h +++ b/MCUME_teensy41/teensydoom/platform_config.h @@ -8,10 +8,9 @@ //#define ST7789 1 //#define TFTSPI1 1 #define HAS_T4_VGA 1 -//#define HIRES 1 //#define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 -//#define INVX 1 #define HAS_EXTFF 1 #else @@ -19,6 +18,7 @@ //#define INVX 1 #define INVY 1 //#define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 #define HAS_EXTFF 1 diff --git a/MCUME_teensy41/teensyframework/AudioPlaySystem.cpp b/MCUME_teensy41/teensyframework/AudioPlaySystem.cpp new file mode 100644 index 0000000..85da04d --- /dev/null +++ b/MCUME_teensy41/teensyframework/AudioPlaySystem.cpp @@ -0,0 +1,415 @@ +#include "emuapi.h" + +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +#include +#define SAMPLERATE AUDIO_SAMPLE_RATE_EXACT +#define CLOCKFREQ 985248 + +#ifndef CUSTOM_SND +PROGMEM static const short square[]={ +32767,32767,32767,32767, +32767,32767,32767,32767, +32767,32767,32767,32767, +32767,32767,32767,32767, +32767,32767,32767,32767, +32767,32767,32767,32767, +32767,32767,32767,32767, +32767,32767,32767,32767, +-32767,-32767,-32767,-32767, +-32767,-32767,-32767,-32767, +-32767,-32767,-32767,-32767, +-32767,-32767,-32767,-32767, +-32767,-32767,-32767,-32767, +-32767,-32767,-32767,-32767, +-32767,-32767,-32767,-32767, +-32767,-32767,-32767,-32767, +}; + +PROGMEM const short noise[] { +-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767, +-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,32767,-32767, +-32767,-32767,32767,-32767,-32767,-32767,32767,-32767,-32767,-32767,32767,-32767,-32767,-32767,32767,-32767, +-32767,-32767,32767,-32767,-32767,-32767,32767,-32767,-32767,-32767,32767,-32767,-32767,32767,32767,-32767, +-32767,-32767,32767,-32767,-32767,32767,32767,-32767,-32767,-32767,32767,-32767,-32767,32767,32767,-32767, +-32767,-32767,32767,-32767,-32767,32767,32767,-32767,-32767,-32767,32767,-32767,32767,32767,32767,-32767, +32767,-32767,32767,-32767,-32767,32767,32767,-32767,-32767,-32767,32767,-32767,32767,32767,32767,-32767, +32767,-32767,32767,-32767,-32767,32767,32767,-32767,-32767,-32767,32767,32767,32767,32767,32767,-32767, +32767,-32767,32767,-32767,-32767,32767,32767,-32767,-32767,-32767,32767,32767,32767,32767,32767,-32767, +32767,-32767,32767,-32767,-32767,32767,32767,-32767,-32767,-32767,-32767,32767,32767,32767,-32767,-32767, +32767,-32767,-32767,-32767,-32767,32767,-32767,-32767,-32767,-32767,32767,32767,32767,32767,32767,-32767, +32767,-32767,32767,-32767,-32767,32767,32767,-32767,-32767,32767,-32767,32767,32767,32767,-32767,-32767, +32767,32767,-32767,-32767,-32767,32767,-32767,-32767,-32767,-32767,32767,32767,32767,32767,32767,-32767, +32767,-32767,32767,-32767,-32767,32767,32767,-32767,32767,32767,-32767,32767,-32767,32767,-32767,-32767, +32767,32767,-32767,-32767,-32767,32767,-32767,-32767,-32767,-32767,32767,32767,32767,32767,32767,-32767, +32767,-32767,32767,-32767,-32767,32767,32767,32767,32767,32767,-32767,32767,-32767,32767,-32767,-32767, +}; + +#define NOISEBSIZE 0x100 + +typedef struct +{ + unsigned int spos; + unsigned int sinc; + unsigned int vol; +} Channel; + +static Channel chan[6] = { + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0} }; + +#endif + +volatile bool playing = false; + + +static void snd_Reset(void) +{ +#ifndef CUSTOM_SND + chan[0].vol = 0; + chan[1].vol = 0; + chan[2].vol = 0; + chan[3].vol = 0; + chan[4].vol = 0; + chan[5].vol = 0; + chan[0].sinc = 0; + chan[1].sinc = 0; + chan[2].sinc = 0; + chan[3].sinc = 0; + chan[4].sinc = 0; + chan[5].sinc = 0; +#endif +} + + +#ifdef CUSTOM_SND +//extern "C" { +void SND_Process(void *sndbuffer, int sndn); +//} +#endif + + +FASTRUN void AudioPlaySystem::snd_Mixer(short * stream, int len ) +{ + if (playing) + { +#ifdef CUSTOM_SND + SND_Process((void*)stream, len); +#else + int i; + long s; + len = len >> 1; + short v0=chan[0].vol; + short v1=chan[1].vol; + short v2=chan[2].vol; + short v3=chan[3].vol; + short v4=chan[4].vol; + short v5=chan[5].vol; + for (i=0;i>8)&0x3f])>>11); + s+=((v1*square[(chan[1].spos>>8)&0x3f])>>11); + s+=((v2*square[(chan[2].spos>>8)&0x3f])>>11); + s+=((v3*noise[(chan[3].spos>>8)&(NOISEBSIZE-1)])>>11); + s+=((v4*noise[(chan[4].spos>>8)&(NOISEBSIZE-1)])>>11); + s+=((v5*noise[(chan[5].spos>>8)&(NOISEBSIZE-1)])>>11); + *stream++ = (short)(s); + *stream++ = (short)(s); + chan[0].spos += chan[0].sinc; + chan[1].spos += chan[1].sinc; + chan[2].spos += chan[2].sinc; + chan[3].spos += chan[3].sinc; + chan[4].spos += chan[4].sinc; + chan[5].spos += chan[5].sinc; + } +#endif + } +} + +void AudioPlaySystem::begin(void) +{ + this->reset(); +} + +void AudioPlaySystem::start(void) +{ + playing = true; +} + +void AudioPlaySystem::setSampleParameters(float clockfreq, float samplerate) { +} + +void AudioPlaySystem::reset(void) +{ + snd_Reset(); +} + +void AudioPlaySystem::stop(void) +{ + //__disable_irq(); + playing = false; + //__enable_irq(); +} + +bool AudioPlaySystem::isPlaying(void) +{ + return playing; +} + + + +void AudioPlaySystem::sound(int C, int F, int V) { +#ifndef CUSTOM_SND + if (C < 6) { + chan[C].vol = V; + chan[C].sinc = F>>1; + } +#endif +} + +void AudioPlaySystem::step(void) { +} + + +/******************************************************************* + Experimental I2S interrupt based sound driver for PCM51xx !!! +*******************************************************************/ + +FLASHMEM static void set_audioClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL4 +{ + if (!force && (CCM_ANALOG_PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_ENABLE)) return; + + CCM_ANALOG_PLL_AUDIO = CCM_ANALOG_PLL_AUDIO_BYPASS | CCM_ANALOG_PLL_AUDIO_ENABLE + | CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2) // 2: 1/4; 1: 1/2; 0: 1/1 + | CCM_ANALOG_PLL_AUDIO_DIV_SELECT(nfact); + + CCM_ANALOG_PLL_AUDIO_NUM = nmult & CCM_ANALOG_PLL_AUDIO_NUM_MASK; + CCM_ANALOG_PLL_AUDIO_DENOM = ndiv & CCM_ANALOG_PLL_AUDIO_DENOM_MASK; + + CCM_ANALOG_PLL_AUDIO &= ~CCM_ANALOG_PLL_AUDIO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_LOCK)) {}; //Wait for pll-lock + + const int div_post_pll = 1; // other values: 2,4 + CCM_ANALOG_MISC2 &= ~(CCM_ANALOG_MISC2_DIV_MSB | CCM_ANALOG_MISC2_DIV_LSB); + if(div_post_pll>1) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_LSB; + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + + CCM_ANALOG_PLL_AUDIO &= ~CCM_ANALOG_PLL_AUDIO_BYPASS;//Disable Bypass +} + +#define AUDIO_SAMPLE_RATE_EXACT 11025.0 //44117.64706 //11025.0 //22050.0 //44117.64706 //31778.0 + +FLASHMEM static void config_sai1() +{ + CCM_CCGR5 |= CCM_CCGR5_SAI1(CCM_CCGR_ON); + double fs = AUDIO_SAMPLE_RATE_EXACT; + // PLL between 27*24 = 648MHz und 54*24=1296MHz + int n1 = 4; //SAI prescaler 4 => (n1*n2) = multiple of 4 + int n2 = 1 + (24000000 * 27) / (fs * 256 * n1); + double C = (fs * 256 * n1 * n2) / 24000000; + int c0 = C; + int c2 = 10000; + int c1 = C * c2 - (c0 * c2); + + set_audioClock(c0, c1, c2, true); + // clear SAI1_CLK register locations + CCM_CSCMR1 = (CCM_CSCMR1 & ~(CCM_CSCMR1_SAI1_CLK_SEL_MASK)) + | CCM_CSCMR1_SAI1_CLK_SEL(2); // &0x03 // (0,1,2): PLL3PFD0, PLL5, PLL4 + + n1 = n1 / 2; //Double Speed for TDM + + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_SAI1_CLK_PRED_MASK | CCM_CS1CDR_SAI1_CLK_PODF_MASK)) + | CCM_CS1CDR_SAI1_CLK_PRED(n1 - 1) // &0x07 + | CCM_CS1CDR_SAI1_CLK_PODF(n2 - 1); // &0x3f + + IOMUXC_GPR_GPR1 = (IOMUXC_GPR_GPR1 & ~(IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL_MASK)) + | (IOMUXC_GPR_GPR1_SAI1_MCLK_DIR | IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL(0)); //Select MCLK + + + // configure transmitter + int rsync = 0; + int tsync = 1; + + I2S1_TMR = 0; + I2S1_TCR1 = I2S_TCR1_RFW(1); + I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_BCP // sync=0; tx is async; + | (I2S_TCR2_BCD | I2S_TCR2_DIV((1)) | I2S_TCR2_MSEL(1)); + I2S1_TCR3 = I2S_TCR3_TCE; + I2S1_TCR4 = I2S_TCR4_FRSZ((2-1)) | I2S_TCR4_SYWD((32-1)) | I2S_TCR4_MF + | I2S_TCR4_FSD | I2S_TCR4_FSE | I2S_TCR4_FSP; + I2S1_TCR5 = I2S_TCR5_WNW((32-1)) | I2S_TCR5_W0W((32-1)) | I2S_TCR5_FBT((32-1)); + + + I2S1_RMR = 0; + I2S1_RCR1 = I2S_RCR1_RFW(1); + I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_RCR2_BCP // sync=0; rx is async; + | (I2S_RCR2_BCD | I2S_RCR2_DIV((1)) | I2S_RCR2_MSEL(1)); + I2S1_RCR3 = I2S_RCR3_RCE; + I2S1_RCR4 = I2S_RCR4_FRSZ((2-1)) | I2S_RCR4_SYWD((32-1)) | I2S_RCR4_MF + | I2S_RCR4_FSE | I2S_RCR4_FSP | I2S_RCR4_FSD; + I2S1_RCR5 = I2S_RCR5_WNW((32-1)) | I2S_RCR5_W0W((32-1)) | I2S_RCR5_FBT((32-1)); + + //CORE_PIN23_CONFIG = 3; // MCLK + CORE_PIN21_CONFIG = 3; // RX_BCLK + CORE_PIN20_CONFIG = 3; // RX_SYNC + CORE_PIN7_CONFIG = 3; // TX_DATA0 + I2S1_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE; + I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE ;//<-- not using DMA */; +} + +FLASHMEM static void config_pt8211() +{ + CCM_CCGR5 |= CCM_CCGR5_SAI1(CCM_CCGR_ON); + double fs = AUDIO_SAMPLE_RATE_EXACT; + // PLL between 27*24 = 648MHz und 54*24=1296MHz + int n1 = 4; //SAI prescaler 4 => (n1*n2) = multiple of 4 + int n2 = 1 + (24000000 * 27) / (fs * 256 * n1); + double C = (fs * 256 * n1 * n2) / 24000000; + int c0 = C; + int c2 = 10000; + int c1 = C * c2 - (c0 * c2); + + set_audioClock(c0, c1, c2, true); + // clear SAI1_CLK register locations + CCM_CSCMR1 = (CCM_CSCMR1 & ~(CCM_CSCMR1_SAI1_CLK_SEL_MASK)) + | CCM_CSCMR1_SAI1_CLK_SEL(2); // &0x03 // (0,1,2): PLL3PFD0, PLL5, PLL4 + + //n1 = n1 / 2; //Double Speed for TDM + + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_SAI1_CLK_PRED_MASK | CCM_CS1CDR_SAI1_CLK_PODF_MASK)) + | CCM_CS1CDR_SAI1_CLK_PRED(n1 - 1) // &0x07 + | CCM_CS1CDR_SAI1_CLK_PODF(n2 - 1); // &0x3f + + IOMUXC_GPR_GPR1 = (IOMUXC_GPR_GPR1 & ~(IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL_MASK)) + | (IOMUXC_GPR_GPR1_SAI1_MCLK_DIR | IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL(0)); //Select MCLK + + + // configure transmitter + int rsync = 0; + int tsync = 1; + + I2S1_TMR = 0; + I2S1_TCR1 = I2S_TCR1_RFW(0); + I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_BCP | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(1); + I2S1_TCR3 = I2S_TCR3_TCE; + I2S1_TCR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(15) | I2S_TCR4_MF | I2S_TCR4_FSD /*| I2S_TCR4_FSE*/ | I2S_TCR4_FSP ; //PT8211 + I2S1_TCR5 = I2S_TCR5_WNW(15) | I2S_TCR5_W0W(15) | I2S_TCR5_FBT(15); + + I2S1_RMR = 0; + I2S1_RCR1 = I2S_RCR1_RFW(0); + I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_RCR2_BCP | I2S_RCR2_MSEL(1)| I2S_RCR2_BCD | I2S_RCR2_DIV(1) ; + I2S1_RCR3 = I2S_RCR3_RCE; + I2S1_RCR4 = I2S_RCR4_FRSZ(1) | I2S_RCR4_SYWD(15) | I2S_RCR4_MF /*| I2S_RCR4_FSE*/ | I2S_RCR4_FSP | I2S_RCR4_FSD; //PT8211 + I2S1_RCR5 = I2S_RCR5_WNW(15) | I2S_RCR5_W0W(15) | I2S_RCR5_FBT(15); + + CORE_PIN21_CONFIG = 3; // RX_BCLK + CORE_PIN20_CONFIG = 3; // RX_SYNC + CORE_PIN7_CONFIG = 3; // TX_DATA0 + I2S1_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE; + I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE ;//<-- not using DMA */; +} + +//DMAMEM __attribute__((aligned(32))) static uint32_t i2s_tx[1024]; + +static bool fillfirsthalf = true; +static uint16_t cnt = 0; +static uint16_t sampleBufferSize = 0; + +static void (*fillsamples)(short * stream, int len) = nullptr; + +static uint32_t * i2s_tx_buffer __attribute__((aligned(32))); +static uint16_t * i2s_tx_buffer16; +static uint16_t * txreg = (uint16_t *)((uint32_t)&I2S1_TDR0 + 2); + +FASTRUN void AudioPlaySystem::AUDIO_isr() { + + *txreg = i2s_tx_buffer16[cnt]; + cnt = cnt + 1; + cnt = cnt & (sampleBufferSize*2-1); + + if (cnt == 0) { + fillfirsthalf = false; + NVIC_SET_PENDING(IRQ_SOFTWARE); + } + else if (cnt == sampleBufferSize) { + fillfirsthalf = true; + NVIC_SET_PENDING(IRQ_SOFTWARE); + } +/* + I2S1_TDR0 = i2s_tx_buffer[cnt]; + cnt = cnt + 1; + cnt = cnt & (sampleBufferSize-1); + if (cnt == 0) { + fillfirsthalf = false; + NVIC_SET_PENDING(IRQ_SOFTWARE); + } + else if (cnt == sampleBufferSize/2) { + fillfirsthalf = true; + NVIC_SET_PENDING(IRQ_SOFTWARE); + } +*/ +} + +FASTRUN void AudioPlaySystem::SOFTWARE_isr() { + //Serial.println("x"); + if (fillfirsthalf) { + fillsamples((short *)i2s_tx_buffer, sampleBufferSize); + arm_dcache_flush_delete((void*)i2s_tx_buffer, (sampleBufferSize/2)*sizeof(uint32_t)); + } + else { + fillsamples((short *)&i2s_tx_buffer[sampleBufferSize/2], sampleBufferSize); + arm_dcache_flush_delete((void*)&i2s_tx_buffer[sampleBufferSize/2], (sampleBufferSize/2)*sizeof(uint32_t)); + } +} + +// display VGA image +FLASHMEM void AudioPlaySystem::begin_audio(int samplesize, void (*callback)(short * stream, int len)) +{ + fillsamples = callback; + i2s_tx_buffer = (uint32_t*)malloc(samplesize*sizeof(uint32_t)); //&i2s_tx[0]; + + if (i2s_tx_buffer == NULL) { + Serial.println("could not allocate audio samples"); + return; + } + memset((void*)i2s_tx_buffer,0, samplesize*sizeof(uint32_t)); + arm_dcache_flush_delete((void*)i2s_tx_buffer, samplesize*sizeof(uint32_t)); + i2s_tx_buffer16 = (uint16_t*)i2s_tx_buffer; + + sampleBufferSize = samplesize; + +#ifdef PT8211 + txreg = (uint16_t *)((uint32_t)&I2S1_TDR0); + config_pt8211(); +#else + txreg = (uint16_t *)((uint32_t)&I2S1_TDR0 + 2); + config_sai1(); +#endif + + attachInterruptVector(IRQ_SAI1, AUDIO_isr); + NVIC_ENABLE_IRQ(IRQ_SAI1); + NVIC_SET_PRIORITY(IRQ_QTIMER3, 0); // 0 highest priority, 255 = lowest priority + NVIC_SET_PRIORITY(IRQ_SAI1, 127); + attachInterruptVector(IRQ_SOFTWARE, SOFTWARE_isr); + NVIC_SET_PRIORITY(IRQ_SOFTWARE, 208); + NVIC_ENABLE_IRQ(IRQ_SOFTWARE); + + I2S1_TCSR |= 1<<8; // start generating TX FIFO interrupts + + Serial.print("Audio sample buffer = "); + Serial.println(samplesize); +} + +FLASHMEM void AudioPlaySystem::end_audio() +{ + if (i2s_tx_buffer != NULL) { + free(i2s_tx_buffer); + } +} + +#endif diff --git a/MCUME_teensy41/teensyframework/AudioPlaySystem.h b/MCUME_teensy41/teensyframework/AudioPlaySystem.h new file mode 100644 index 0000000..6d2e23b --- /dev/null +++ b/MCUME_teensy41/teensyframework/AudioPlaySystem.h @@ -0,0 +1,31 @@ +#ifndef audioplaysystem_h_ +#define audioplaysystem_h_ + +#ifdef HAS_SND + +#include "platform_config.h" + +class AudioPlaySystem +{ +public: + AudioPlaySystem(void) { }; + void begin(void); + void setSampleParameters(float clockfreq, float samplerate); + void reset(void); + void start(void); + void stop(void); + bool isPlaying(void); + void sound(int C, int F, int V); + void buzz(int size, int val); + void step(void); + static void snd_Mixer(short * stream, int len ); + void begin_audio(int samplesize, void (*callback)(short * stream, int len)); + void end_audio(); + static void AUDIO_isr(void); + static void SOFTWARE_isr(void); +}; + + +#endif + +#endif diff --git a/MCUME_teensy41/teensyframework/emuapi.cpp b/MCUME_teensy41/teensyframework/emuapi.cpp new file mode 100644 index 0000000..e128cca --- /dev/null +++ b/MCUME_teensy41/teensyframework/emuapi.cpp @@ -0,0 +1,2042 @@ +#define KEYMAP_PRESENT 1 + +extern "C" { + #include "emuapi.h" + #include "iopins.h" +} + +#include + +#ifdef HAS_USB +#include "USBHost_t36.h" // Read this header first for key info +USBHost myusb; +USBHub hub1(myusb); +#ifdef HAS_USBKEY +KeyboardController keyboard1(myusb); +USBHIDParser hid1(myusb); +MouseController mouse1(myusb); +#endif +#ifdef HAS_USBMIDI +MIDIDevice midi1(myusb); +#endif +#ifdef HAS_USBJOY +#define COUNT_JOYSTICKS 4 +JoystickController joysticks[COUNT_JOYSTICKS](myusb); +#endif +#endif + +static bool emu_writeConfig(void); +static bool emu_readConfig(void); +static bool emu_eraseConfig(void); +static bool emu_writeGfxConfig(char * display_type); +static int emu_readGfxConfig(void); + +static bool mouseDetected = false; +static bool keyboardDetected = false; +static uint8_t usbnavpad=0; + +#include +static File file; + +#define MAX_FILES 64 +#define AUTORUN_FILENAME "autorun.txt" +#define GFX_CFG_FILENAME "gfxmode.txt" + +#define MAX_FILENAME_SIZE 34 +#define MAX_MENULINES 9 +#define TEXT_HEIGHT 16 +#define TEXT_WIDTH 8 +#define MENU_FILE_XOFFSET (2*TEXT_WIDTH) +#define MENU_FILE_YOFFSET (2*TEXT_HEIGHT) +#define MENU_FILE_W (MAX_FILENAME_SIZE*TEXT_WIDTH) +#define MENU_FILE_H (MAX_MENULINES*TEXT_HEIGHT) +#define MENU_FILE_BGCOLOR RGBVAL16(0x00,0x00,0x40) +#define MENU_JOYS_YOFFSET (12*TEXT_HEIGHT) +#define MENU_VBAR_XOFFSET (0*TEXT_WIDTH) +#define MENU_VBAR_YOFFSET (MENU_FILE_YOFFSET) + +#define MENU_TFT_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) +#define MENU_TFT_YOFFSET (MENU_VBAR_YOFFSET+32) +#define MENU_VGA_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) +#define MENU_VGA_YOFFSET (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37) + +#include "t4_dsp.h" +T4_DSP tft; + +static int nbFiles=0; +static int curFile=0; +static int topFile=0; +static char selection[MAX_FILENAME_PATH]=""; +static char second_selection[MAX_FILENAME_PATH]=""; +static char files[MAX_FILES][MAX_FILENAME_SIZE]; +static char selected_filename[MAX_FILENAME_SIZE]=""; +static char second_selected_filename[MAX_FILENAME_SIZE]=""; +static bool menuRedraw=true; +static bool autorun=false; +static bool vgahires=false; + + +static const unsigned short * keys; +#ifdef TEECOMPUTER +static unsigned char keymatrix[6]; +static int keymatrix_hitrow=-1; +static uint32_t keypress_t_ms=0; +static uint32_t last_t_ms=0; +static uint32_t hundred_ms_cnt=0; +static bool ledflash_toggle=false; +#endif +static bool key_extmode=false; +static bool key_sh=false; +static bool key_fn=false; + +static boolean joySwapped = false; +static uint16_t bLastState; +#ifdef PIN_JOY2_A1X +static int xRef; +static int yRef; +#endif +static bool menuOn=true; + + +/******************************** + * Generic output and malloc +********************************/ +void emu_printf(const char * text) +{ + Serial.println(text); +} + +void emu_printf(int val) +{ + Serial.println(val); +} + +void emu_printi(int val) +{ + Serial.println(val,HEX); +} + +void emu_printh(int val) +{ + Serial.println(val,HEX); +} + +static int malbufpt = 0; +static char malbuf[EXTRA_HEAP]; + +void * emu_Malloc(unsigned int size) +{ + void * retval = malloc(size); + if (!retval) { + emu_printf("failled to allocate"); + emu_printf(size); + emu_printf("fallback"); + if ( (malbufpt+size) < sizeof(malbuf) ) { + retval = (void *)&malbuf[malbufpt]; + malbufpt += size; + } + else { + emu_printf("failure to allocate"); + } + } + else { + emu_printf("could allocate dynamic "); + emu_printf(size); + } + + return retval; +} + +void * emu_MallocI(unsigned int size) +{ + void * retval = NULL; + + if ( (malbufpt+size) < sizeof(malbuf) ) { + retval = (void *)&malbuf[malbufpt]; + malbufpt += size; + emu_printf("could allocate static "); + emu_printf(size); + } + else { + emu_printf("failure to allocate"); + } + + return retval; +} +void emu_Free(void * pt) +{ + free(pt); +} + +#define SMEMPOOL (0x800000) +EXTMEM static unsigned char slowmem[SMEMPOOL]; +static int slowmempt = 0; + +void * emu_SMalloc(unsigned int size) +{ + void * mem = (void*)&slowmem[slowmempt]; + slowmempt += size; + + if ( slowmempt > SMEMPOOL ) { + mem = NULL; + emu_printf("failure to allocate slow"); + } + else { + emu_printf("could allocate slow static "); + emu_printf(size); + } + return mem; +} + +void emu_SFree(void * pt) +{ +} +/******************************** + * Input and keyboard +********************************/ +#ifdef PIN_JOY2_A1X +int emu_ReadAnalogJoyX(int min, int max) +{ + int val = analogRead(PIN_JOY2_A1X); +#if INVX + val = 4095 - val; +#endif + val = val-xRef; + val = ((val*140)/100); + if ( (val > -512) && (val < 512) ) val = 0; + val = val+2048; + return (val*(max-min))/4096; +} +#endif + +#ifdef PIN_JOY2_A2Y +int emu_ReadAnalogJoyY(int min, int max) +{ + int val = analogRead(PIN_JOY2_A2Y); +#if INVY + val = 4095 - val; +#endif + val = val-yRef; + val = ((val*120)/100); + if ( (val > -512) && (val < 512) ) val = 0; + //val = (val*(max-min))/4096; + val = val+2048; + //return val+(max-min)/2; + return (val*(max-min))/4096; +} +#endif + +static uint16_t readAnalogJoystick(void) +{ + uint16_t joysval = 0; + +#ifdef PIN_JOY2_A1X + int xReading = emu_ReadAnalogJoyX(0,256); + if (xReading > 128) joysval |= MASK_JOY2_LEFT; + else if (xReading < 128) joysval |= MASK_JOY2_RIGHT; + + int yReading = emu_ReadAnalogJoyY(0,256); + if (yReading < 128) joysval |= MASK_JOY2_UP; + else if (yReading > 128) joysval |= MASK_JOY2_DOWN; +#endif + +#ifdef PIN_JOY2_BTN + joysval |= (digitalRead(PIN_JOY2_BTN) == HIGH ? 0 : MASK_JOY2_BTN); +#endif + return (joysval); +} + + +int emu_SwapJoysticks(int statusOnly) { + if (!statusOnly) { + if (joySwapped) { + joySwapped = false; + } + else { + joySwapped = true; + } + } + return(joySwapped?1:0); +} + +int emu_GetPad(void) +{ + return(bLastState/*|((joySwapped?1:0)<<7)*/); +} + +int emu_ReadKeys(void) +{ + uint16_t retval; + uint16_t j1 = readAnalogJoystick(); + uint16_t j2 = 0; + + // Second joystick +#ifdef PIN_JOY1_1 + if ( digitalRead(PIN_JOY1_1) == LOW ) j2 |= MASK_JOY2_UP; +#endif +#ifdef PIN_JOY1_2 + if ( digitalRead(PIN_JOY1_2) == LOW ) j2 |= MASK_JOY2_DOWN; +#endif +#ifdef PIN_JOY1_3 + if ( digitalRead(PIN_JOY1_3) == LOW ) j2 |= MASK_JOY2_RIGHT; +#endif +#ifdef PIN_JOY1_4 + if ( digitalRead(PIN_JOY1_4) == LOW ) j2 |= MASK_JOY2_LEFT; +#endif +#ifdef PIN_JOY1_BTN + if ( digitalRead(PIN_JOY1_BTN) == LOW ) j2 |= MASK_JOY2_BTN; +#endif + if (joySwapped) { + retval = ((j1 << 8) | j2); + } + else { + retval = ((j2 << 8) | j1); + } + + if (usbnavpad & MASK_JOY2_UP) retval |= MASK_JOY2_UP; + if (usbnavpad & MASK_JOY2_DOWN) retval |= MASK_JOY2_DOWN; + if (usbnavpad & MASK_JOY2_LEFT) retval |= MASK_JOY2_LEFT; + if (usbnavpad & MASK_JOY2_RIGHT) retval |= MASK_JOY2_RIGHT; + if (usbnavpad & MASK_JOY2_BTN) retval |= MASK_JOY2_BTN; + if (usbnavpad & MASK_KEY_USER1) retval |= MASK_KEY_USER1; + if (usbnavpad & MASK_KEY_USER2) retval |= MASK_KEY_USER2; + +#ifdef PIN_KEY_USER1 + if ( digitalRead(PIN_KEY_USER1) == LOW ) retval |= MASK_KEY_USER1; +#endif +#ifdef PIN_KEY_USER2 + if ( digitalRead(PIN_KEY_USER2) == LOW ) retval |= MASK_KEY_USER2; +#endif +#ifdef PIN_KEY_USER3 + if ( digitalRead(PIN_KEY_USER3) == LOW ) retval |= MASK_KEY_USER3; +#endif +#ifdef PIN_KEY_USER4 + if ( digitalRead(PIN_KEY_USER4) == LOW ) retval |= MASK_KEY_USER4; +#endif + +#ifdef TEECOMPUTER + keymatrix_hitrow = -1; + unsigned char row; + unsigned short cols[6]={KCOLOUT1,KCOLOUT2,KCOLOUT3,KCOLOUT4,KCOLOUT5,KCOLOUT6}; + for (int i=0;i<6;i++){ + pinMode(cols[i],OUTPUT); + digitalWrite(cols[i], 0); + row=0; + row |= (digitalRead(KROWIN1) ? 0 : 0x01); + row |= (digitalRead(KROWIN2) ? 0 : 0x02); + row |= (digitalRead(KROWIN3) ? 0 : 0x04); + row |= (digitalRead(KROWIN4) ? 0 : 0x08); + row |= (digitalRead(KROWIN5) ? 0 : 0x10); + row |= (digitalRead(KROWIN6) ? 0 : 0x20); + row |= (digitalRead(KROWIN7) ? 0 : 0x40); + digitalWrite(cols[i], 1); + pinMode(cols[i],INPUT_DISABLE); + keymatrix[i]=row; + } + + bool fn_pressed=false; + if ( keymatrix[5] & 0x08 ) {fn_pressed=true; keymatrix[5] &= ~0x08;}; + + bool sh_pressed=false; + if ( keymatrix[5] & 0x10 ) {sh_pressed=true; keymatrix[5] &= ~0x10;}; + + for (int i=0;i<6;i++){ + row = keymatrix[i]; + if (row) keymatrix_hitrow=i; + } + + //6,9,15,8,7,22 +#if INVX + if ( row & 0x40 ) retval |= MASK_JOY2_LEFT; + if ( row & 0x20 ) retval |= MASK_JOY2_RIGHT; +#else + if ( row & 0x20 ) retval |= MASK_JOY2_LEFT; + if ( row & 0x40 ) retval |= MASK_JOY2_RIGHT; +#endif +#if INVY + if ( row & 0x4 ) retval |= MASK_JOY2_DOWN; + if ( row & 0x1 ) retval |= MASK_JOY2_UP; +#else + if ( row & 0x1 ) retval |= MASK_JOY2_DOWN; + if ( row & 0x4 ) retval |= MASK_JOY2_UP; +#endif + if ( row & 0x02 ) retval |= MASK_JOY2_BTN; + + +#ifdef EXTPAD + if ( sh_pressed ) retval |= MASK_KEY_USER3; + if ( fn_pressed ) retval |= MASK_KEY_USER1; + digitalWrite(KLED, 0); +#else + // Handle LED flash + uint32_t time_ms=millis(); + if ((time_ms-last_t_ms) > 100) { + last_t_ms = time_ms; + if (ledflash_toggle == false) { + ledflash_toggle = true; + } + else { + ledflash_toggle = false; + } + } + + if ( sh_pressed ) { + key_sh = true; + } + else { + key_sh = false; + if ( fn_pressed ) { + if (key_fn == false) + { + // Release to Press transition + if (hundred_ms_cnt == 0) { + keypress_t_ms=time_ms; + hundred_ms_cnt += 1; // 1 + } + else { + hundred_ms_cnt += 1; // 2 + if (hundred_ms_cnt >= 2) + { + hundred_ms_cnt = 0; + if ( (time_ms-keypress_t_ms) < 500) + { + if (key_extmode == false) + { + key_extmode = true; + } + else + { + key_extmode = false; + } + } + } + } + } + else { + // Keep press + if (hundred_ms_cnt == 1) { + if ((millis()-keypress_t_ms) > 1000) + { + if (key_extmode == false) + { + key_extmode = true; + } + else + { + key_extmode = false; + } + hundred_ms_cnt = 0; + } + } + } + key_fn = true; + } + else { + key_fn = false; + } + } + + // Handle LED + if (key_extmode == true) { + digitalWrite(KLED, (ledflash_toggle?1:0)); + } + else { + if ( (key_fn == true) || (key_sh == true) ) { + digitalWrite(KLED, 1); + } + else { + digitalWrite(KLED, 0); + } + } + + if ( key_fn ) retval |= MASK_KEY_USER2; + if ( ( key_fn ) && (keymatrix[4] == 0x10 )) retval |= MASK_KEY_USER1; +#endif + + if ( (fn_pressed) && (sh_pressed) ) +#else + if ( ((retval & (MASK_KEY_USER1+MASK_KEY_USER2)) == (MASK_KEY_USER1+MASK_KEY_USER2)) + || (retval & MASK_KEY_USER4 ) ) +#endif + { +// Reset procedure T3.X and T4.0 by Frank Boesing !! +#if defined(__IMXRT1052__) || defined(__IMXRT1062__) + uint32_t tmp = SNVS_LPCR; // save control register + + SNVS_LPSR |= 1; + + // disable alarm + SNVS_LPCR &= ~0x02; + while (SNVS_LPCR & 0x02); + + __disable_irq(); + //get Time: + uint32_t lsb, msb; + do { + msb = SNVS_LPSRTCMR; + lsb = SNVS_LPSRTCLR; + } while ( (SNVS_LPSRTCLR != lsb) | (SNVS_LPSRTCMR != msb) ); + uint32_t secs = (msb << 17) | (lsb >> 15); + + //set alarm + secs += 2; + SNVS_LPTAR = secs; + while (SNVS_LPTAR != secs); + + SNVS_LPCR = tmp | 0x02; // restore control register and set alarm + while (!(SNVS_LPCR & 0x02)); + + SNVS_LPCR |= (1 << 6); // turn off power + while (1) asm("wfi"); +#else + *(volatile uint32_t *)0xE000ED0C = 0x5FA0004; + while (true) { + ; + } +#endif + } + + emu_GetJoystick(); + + return (retval); +} + +unsigned short emu_DebounceLocalKeys(void) +{ + uint16_t bCurState = emu_ReadKeys(); + uint16_t bClick = bCurState & ~bLastState; + bLastState = bCurState; + + return (bClick); +} + +int emu_ReadI2CKeyboard(void) { + int retval=0; +#ifdef TEECOMPUTER + if (key_extmode) { + if (key_fn) { + keys = (const unsigned short *)key_map5; // fn-extra + } + else if (key_sh) { + keys = (const unsigned short *)key_map4; // shift-functionkeys + } + else { + keys = (const unsigned short *)key_map3; // def-digitkeys + } + } + else { + if (key_fn) { + keys = (const unsigned short *)key_map2; // fn-shiftothers + } + else if (key_sh) { + keys = (const unsigned short *)key_map1; // shift-uppercase + } + else { + keys = (const unsigned short *)key_map0; // def-lowercase + } + } + + + if (keymatrix_hitrow >=0 ) { + unsigned short match = ((unsigned short)keymatrix_hitrow<<8) | keymatrix[keymatrix_hitrow]; + for (unsigned int i=0; i= 128) { + midiDataCnt = 0; + midiLastCmd = value; + switch (value & 0xF0) { + case 128: // 0x80 + midiCmdNbParam = 2; + //Serial.print("note off: "); + //Serial.println(value&0xf); + break; + case 144: //0x90 + midiCmdNbParam = 2; + //Serial.print("note on: "); + //Serial.println(value&0xf); + break; + case 160: //0xA0 + midiCmdNbParam = 2; + //Serial.print("aftertouch: "); // rare + //Serial.println(value&0xf); + break; + case 176: //0xB0 + midiCmdNbParam = 2; + //Serial.print("continuous controller: "); + //Serial.println(value&0xf); + break; + case 192: //0xC0 + midiCmdNbParam = 1; + //Serial.print("patch change: "); //some + //Serial.println(value&0xf); + break; + case 208: //0xD0 + midiCmdNbParam = 1; + Serial.print("channel pressure: "); + Serial.println(value&0xf); + break; + case 224: //0xE0 + midiCmdNbParam = 2; + //Serial.print("pitch bend: "); + //Serial.println(value&0xf); + break; + case 240: //0xF0 + // non-musical commands + switch (value) { + case 0xF0: + //Serial.println("NI: System Exclusive"); + break; + case 0xF1: + //Serial.println("NI: System Common - MIDI Time Code Quarter Frame"); + break; + case 0xF2: + midiCmdNbParam = 2; + break; + case 0xF3: + //Serial.println("NI: System Common - Song Select"); + break; + case 0xF6: + //Serial.println("NI: System Common - Tune Request"); + break; + case 0xF8: + //Serial.println("System Real Time - Timing Clock"); + midi1.sendRealTime(value, 0); + break; + case 0xFA: + //Serial.println("System Real Time - Start"); + midi1.sendRealTime(value, 0); + break; + case 0xFB: + //Serial.println("System Real Time - Continue"); + midi1.sendRealTime(value, 0); + break; + case 0xFC: + //Serial.println("System Real Time - Stop"); + midi1.sendRealTime(value, 0); + break; + case 0xFE: + //Serial.println("System Real Time - Active Sensing"); + midi1.sendRealTime(value, 0); + break; + case 0xFF: + //Serial.println("System Real Time - System Reset"); + midi1.sendRealTime(value, 0); + break; + } + //SystemExclusive = 0xF0, // System Exclusive + //TimeCodeQuarterFrame = 0xF1, // System Common - MIDI Time Code Quarter Frame + //SongPosition = 0xF2, // System Common - Song Position Pointer + //SongSelect = 0xF3, // System Common - Song Select + //TuneRequest = 0xF6, // System Common - Tune Request + //Clock = 0xF8, // System Real Time - Timing Clock + //Start = 0xFA, // System Real Time - Start + //Continue = 0xFB, // System Real Time - Continue + //Stop = 0xFC, // System Real Time - Stop + //ActiveSensing = 0xFE, // System Real Time - Active Sensing + //SystemReset = 0xFF, // System Real Time - System Reset + break; + default: + Serial.print("??: "); + Serial.println(value&0xf); + break; + } + } + else { + if (midiDataCnt<16) midiBuffer[midiDataCnt++] = value ; + if ( (midiLastCmd & 0xF0) == 240) { + if (midiLastCmd == 0xF2) { + if (midiDataCnt == midiCmdNbParam) { + //Serial.println("System Common - Song Position Pointer"); + midi1.sendSongPosition(((int)midiBuffer[1]<<7)+(int)midiBuffer[0], 0); + } + } + else { + Serial.println(value); + } + } + else if (midiDataCnt == midiCmdNbParam) { + unsigned char chan = (midiLastCmd&0xf)+1; + //Serial.print("ch "); + //Serial.println(chan); + switch (midiLastCmd & 0xF0) { + case 128: //0x80 + //Serial.print("note off: "); + midi1.sendNoteOff(midiBuffer[0], midiBuffer[1], chan); + break; + case 144: //0x90 + //Serial.print("note on: "); + midi1.sendNoteOn(midiBuffer[0], midiBuffer[1], chan); + break; + case 160: //0xA0 + //Serial.print("aftertouch: "); + midi1.sendPolyPressure(midiBuffer[0], midiBuffer[1], chan); + break; + case 176: //0xB0 + //Serial.print("continuous controller: "); + midi1.sendControlChange(midiBuffer[0], midiBuffer[1], chan); + break; + case 192: //0xC0 + //Serial.print("patch change: "); + midi1.sendProgramChange(midiBuffer[0], chan); + break; + case 208: //0xD0 + //Serial.print("channel pressure: "); + midi1.sendAfterTouch(midiBuffer[0], chan); + break; + case 224: //0xE0 + //Serial.print("pitch bend: "); + midi1.sendPitchBend((((int)midiBuffer[1]<<7)+(int)midiBuffer[0])-8192, chan); + break; + default: + Serial.print("??: "); + break; + } + } + } +#endif +} + +/******************************** + * Menu file loader UI +********************************/ +#ifdef FILEBROWSER +static int readNbFiles(void) { + int totalFiles = 0; + + File entry; + file = SD.open(selection); + while ( (true) && (totalFiles=0) { + menuRedraw=true; + curFile -= 9; + } else if (curFile!=0) { + menuRedraw=true; + curFile--; + } + } + else if ( (bClick & MASK_JOY2_DOWN) || (bClick & MASK_JOY1_DOWN) ) { + if ((curFile<(nbFiles-1)) && (nbFiles)) { + curFile++; + menuRedraw=true; + } + } + else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { + if ((curFile<(nbFiles-9)) && (nbFiles)) { + curFile += 9; + menuRedraw=true; + } + else if ((curFile<(nbFiles-1)) && (nbFiles)) { + curFile++; + menuRedraw=true; + } + } + + if (menuRedraw && nbFiles) { + int fileIndex = 0; + tft.drawRectNoDma(MENU_FILE_XOFFSET,MENU_FILE_YOFFSET, MENU_FILE_W, MENU_FILE_H, MENU_FILE_BGCOLOR); +// if (curFile <= (MAX_MENULINES/2-1)) topFile=0; +// else topFile=curFile-(MAX_MENULINES/2); + if (curFile <= (MAX_MENULINES-1)) topFile=0; + else topFile=curFile-(MAX_MENULINES/2); + + //Serial.print("curfile: "); + //Serial.println(curFile); + //Serial.print("topFile: "); + //Serial.println(topFile); + + int i=0; + while (i=nbFiles) { + // no more files + break; + } + char * filename = &files[fileIndex][0]; + if (fileIndex >= topFile) { + if ((i+topFile) < nbFiles ) { + if ((i+topFile)==curFile) { + tft.drawTextNoDma(MENU_FILE_XOFFSET,i*TEXT_HEIGHT+MENU_FILE_YOFFSET, filename, RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); + strcpy(selected_filename,filename); + } + else { + tft.drawTextNoDma(MENU_FILE_XOFFSET,i*TEXT_HEIGHT+MENU_FILE_YOFFSET, filename, RGBVAL16(0xff,0xff,0xff), MENU_FILE_BGCOLOR, true); + } + } + i++; + } + fileIndex++; + } + + +// tft.drawTextNoDma(48,MENU_JOYS_YOFFSET+8, (emu_SwapJoysticks(1)?(char*)"SWAP=1":(char*)"SWAP=0"), RGBVAL16(0x00,0xff,0xff), RGBVAL16(0x00,0x00,0xff), false); + tft.drawTextNoDma(48,MENU_JOYS_YOFFSET+8, "FLOPPY2:", RGBVAL16(0x00,0xff,0xff), RGBVAL16(0x00,0x00,0xff), false); + tft.drawRectNoDma(120,MENU_JOYS_YOFFSET+8, MENU_FILE_W, 8, RGBVAL16(0x00,0x00,0x00)); + tft.drawTextNoDma(120,MENU_JOYS_YOFFSET+8, second_selected_filename, RGBVAL16(0xff,0xff,0xff), RGBVAL16(0x00,0x00,0x00), false); + menuRedraw=false; + } + + return (action); +} + +int menuActive(void) +{ + return (menuOn?1:0); +} + +void toggleMenu(int on) { + if (on) { + menuOn=true; + backgroundMenu(); + } else { + menuOn = false; + } +} + +char * menuSelection(void) +{ + return (selection); +} + +char * menuSecondSelection(void) +{ + return (second_selection); +} +#endif + +/******************************** + * OSKB handling +********************************/ +static bool oskbOn = false; +static int cxpos = 0; +static int cypos = 0; +static uint16_t oskbBLastState = 0; +#define OSKBHEIGHT 4 +#define OSKBXOFF 16 +#define OSKBYOFF 0 + +static void lineOSKB(int xoff, bool bottom, char * str, int row) +{ + char c[4] = {' ',0,' ',0}; + const char * cpt = str; + int i=0; + int fb_width,fb_height,fbstride; + + fbstride = tft.get_frame_buffer_size(&fb_width, &fb_height); + int ypos = (bottom?(fb_height-2*8):0); + int line = row + (bottom?2:0); + while ((c[1] = *cpt++)) + { + uint16_t bg; + if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0); + else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff); + if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff); + tft.drawText(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); + i++; + } +} + +static int linelenOSKB() { + if (cypos == 0) return strlen(keylables_map0_0); + else if (cypos == 1) return strlen(keylables_map0_1); + else if (cypos == 2) return strlen(keylables_map0_2); + else return strlen(keylables_map0_3); +} + +static void drawOSKB() { + if (key_extmode) { + if (key_fn) { + lineOSKB(16,false, keylables_map5_0, 0); + lineOSKB(8, false, keylables_map5_1, 1); + lineOSKB(0, true, keylables_map5_2, 0); + lineOSKB(96,true, keylables_map5_3, 1); + } + else if (key_sh) { + lineOSKB(16,false, keylables_map4_0, 0); + lineOSKB(8, false, keylables_map4_1, 1); + lineOSKB(0, true, keylables_map4_2, 0); + lineOSKB(96,true, keylables_map4_3, 1); + } + else { + lineOSKB(16,false, keylables_map3_0, 0); + lineOSKB(8, false, keylables_map3_1, 1); + lineOSKB(0, true, keylables_map3_2, 0); + lineOSKB(96,true, keylables_map3_3, 1); + } + } + else { + if (key_fn) { + lineOSKB(16,false, keylables_map2_0, 0); + lineOSKB(8, false, keylables_map2_1, 1); + lineOSKB(0, true, keylables_map2_2, 0); + lineOSKB(96,true, keylables_map2_3, 1); + } + else if (key_sh) { + lineOSKB(16,false, keylables_map1_0, 0); + lineOSKB(8, false, keylables_map1_1, 1); + lineOSKB(0, true, keylables_map1_2, 0); + lineOSKB(96,true, keylables_map1_3, 1); + } + else { + lineOSKB(16,false, keylables_map0_0, 0); + lineOSKB(8, false, keylables_map0_1, 1); + lineOSKB(0, true, keylables_map0_2, 0); + lineOSKB(96,true, keylables_map0_3, 1); + } + } +} + +int handleOSKB(void) { + int retval = 0; + if (oskbOn) { + uint16_t bClick = bLastState & ~oskbBLastState; + oskbBLastState = bLastState; + bool updated = true; + if (bClick & MASK_KEY_USER1) + { + } + else if (bClick & MASK_JOY2_RIGHT) + { + cxpos++; + if (cxpos >= linelenOSKB()) cxpos = 0; + } + else if (bClick & MASK_JOY2_LEFT) + { + cxpos--; + if (cxpos < 0) cxpos = linelenOSKB()-1; + } + else if (bClick & MASK_JOY2_DOWN) + { + cypos++; + if (cypos >= OSKBHEIGHT) cypos = 0; + if (cxpos >= linelenOSKB()) cxpos = linelenOSKB()-1; + } + else if (bClick & MASK_JOY2_UP) + { + cypos--; + if (cypos < 0) cypos = OSKBHEIGHT-1; + if (cxpos >= linelenOSKB()) cxpos = linelenOSKB()-1; + } + else if (oskbBLastState & MASK_JOY2_BTN) + { + //if (retval) { toggleOSKB(false); updated=false; }; + } + else { + updated=false; + } + /*if (updated)*/ drawOSKB(); + } + return retval; +} + +void toggleOSKB(int forceon) { + if (forceon) { + oskbOn = true; + drawOSKB(); + } + else { + if (oskbOn) { + oskbOn = false; + } + else { + oskbOn = true; + drawOSKB(); + } + } +} + + + +/******************************** + * File IO +********************************/ +static File file_handlers[NB_FILE_HANDLER]; + +static void FileHandlersInit(void) { + for (int i=0; i= 0) { + if ((file_handlers[handler] = SD.open(filepath, O_READ))) { + // emu_printi(handler+1); + retval = handler+1; + } + else { + file_handlers[handler] = file; + emu_printf("FileOpen failed"); + } + } + return (retval); +#endif +} + +int emu_FileRead(void * buf, int size, int handler) +{ +// emu_printf("FileRead"); +// emu_printi(handler); +#ifdef HCFH + return (file.read(buf, size)); +#else + return (getFileHandler(handler).read(buf, size)); +#endif +} + +int emu_FileWrite(void * buf, int size, int handler) +{ +// emu_printf("emu_FileWrite"); +// emu_printi(handler); +#ifdef HCFH + return (file.write(buf, size)); +#else + return (getFileHandler(handler).write(buf, size)); +#endif +} + +int emu_FileGetc(int handler) { +// emu_printf("FileGetc"); +// emu_printi(handler); +#ifdef HCFH + unsigned char c; + int retval = file.read(&c, 1); + if (retval != 1) { + emu_printf("emu_FileGetc failed"); + } + return (int)c; +#else + unsigned char c; + int retval = getFileHandler(handler).read(&c, 1); + if (retval != 1) { + emu_printf("emu_FileGetc failed"); + } + return (int)c; +#endif +} + +int emu_FileSeek(int handler, int seek, int origin) +{ +// emu_printf("FileSeek"); +// emu_printi(handler); +// emu_printi(seek); +#ifdef HCFH + file.seek(seek); + return (seek); +#else + getFileHandler(handler).seek(seek); + return (seek); +#endif +} + +int emu_FileTell(int handler) { +// emu_printf("FileTell"); +// emu_printi(handler); +#ifdef HCFH + return (50); +#else + File file = getFileHandler(handler); + return (emu_FileSize((char*)file.name())); +#endif +} + + +void emu_FileClose(int handler) +{ +// emu_printf("FileClose"); +// emu_printi(handler); +#ifdef HCFH + file.close(); +#else + getFileHandler(handler).close(); + file_handlers[handler-1] = file; +#endif +} + + +static File lofile; + +unsigned int emu_FileSize(const char * filepath) +{ + unsigned int filesize=0; + emu_printf(filepath); + if ((lofile = SD.open(filepath, O_READ))) + { + emu_printf("filesize is..."); + filesize = lofile.size(); + emu_printf(filesize); + lofile.close(); + } + else { + emu_printf("filesize failed"); + } + return(filesize); +} + +unsigned int emu_LoadFile(const char * filepath, void * buf, int size) +{ + unsigned int filesize = 0; + emu_printf("LoadFile..."); + emu_printf(filepath); + if ((lofile = SD.open(filepath, O_READ))) + { + filesize = lofile.size(); + emu_printf(filesize); + if ((unsigned int)size >= filesize) + { + if (lofile.read(buf, filesize) != filesize) + { + emu_printf("File read failed"); + } + } + lofile.close(); + } + return(filesize); +} + +unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek) +{ + unsigned int filesize = 0; + emu_printf("LoadFileSeek..."); + emu_printf(filepath); + if ((lofile = SD.open(filepath, O_READ))) + { + lofile.seek(seek); + emu_printf(size); + if (lofile.read(buf, size) != (unsigned int)size) { + emu_printf("File read failed"); + } + lofile.close(); + } + return(filesize); +} + +static bool emu_writeConfig(void) +{ + bool retval = false; + if ((lofile = SD.open(ROMSDIR "/" AUTORUN_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(selection, strlen(selection)) != strlen(selection)) { + emu_printf("Config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + return retval; +} + +static bool emu_readConfig(void) +{ + bool retval = false; + + if ((lofile = SD.open(ROMSDIR "/" AUTORUN_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + unsigned int sizeread = lofile.read(selection, filesize); + if (sizeread != filesize) { + emu_printf("Config read failed"); + } + else { + if (sizeread == filesize) + { + selection[filesize]=0; + retval = true; + } + } + lofile.close(); + } + return retval; +} + +static bool emu_eraseConfig(void) +{ + SD.remove (ROMSDIR "/" AUTORUN_FILENAME); +} + +static bool emu_writeGfxConfig(char * display_type) +{ + bool retval = false; + SD.remove ("/" GFX_CFG_FILENAME); + if (strcmp(display_type, "VGA")) { + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(display_type, strlen(display_type)) != strlen(display_type)) { + emu_printf("GFX config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + } + return retval; +} + +#define CFG_VGA 0 +#define CFG_ILI 1 +#define CFG_ST 2 + +static int emu_readGfxConfig(void) +{ + int retval = CFG_VGA; // No file = VGA + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + if (filesize == 2) // "ST" + { + retval = CFG_ST; + } + else if (filesize == 3) // "ILI" + { + retval = CFG_ILI; + } + lofile.close(); + } + return retval; +} + +/******************************** + * File IO compatibility +********************************/ +#ifdef HAS_EXTFF + +#include "ff.h" + +typedef struct { + File f; + int offset; + int size; + int used; +} FileDesc; + +typedef int * FIL; + + + +#define NO_MMAP_HANDLES 32 + +static FileDesc fds[NO_MMAP_HANDLES]; +static int nextHandle=0; + +static void freeHandle(int h) { + fds[h].used = 0; +} + + +static int getFreeHandle() { + int n=NO_MMAP_HANDLES; + while (fds[nextHandle].used!=0 && n!=0) { + nextHandle++; + if (nextHandle==NO_MMAP_HANDLES) nextHandle=0; + n-1; + } + if (n==0) { + emu_printf("getFreeHandle error"); + return; + } + + int r=nextHandle; + fds[r].used = 1; + nextHandle++; + if (nextHandle==NO_MMAP_HANDLES) nextHandle=0; + + return r; +} + +FRESULT f_open (FIL* fp, const char * path, unsigned char mode) +{ + emu_printf("fopen"); + emu_printf((char*)path); + int i=getFreeHandle(); + emu_printf(i); + fds[i].f = SD.open(path, O_READ); + *fp = i; + if (fds[i].f) { + fds[i].size = fds[i].f.size(); + emu_printi(fds[i].size); + return(FR_OK); + } + emu_printf("error"); + freeHandle(fds[i].f); + return(FR_NO_FILE); +} + +FRESULT f_close (FIL* fp) +{ + int i = *fp; + emu_printf("fclose"); + emu_printi(i); + fds[i].f.close(); + freeHandle(i); + return(FR_OK); +} + +FRESULT f_read (FIL* fp, void* buff, unsigned int btr, unsigned int * br) +{ + int i = *fp; + + if (btr < 64738) { + int nr = fds[i].f.read(buff, btr); + //emu_printf("fread"); + //emu_printi(btr); + //emu_printi(nr); + *br = nr; + if (nr <= 0) + return(FR_DISK_ERR); + else + return(FR_OK); + } + + unsigned char buffer[256]; + + int remaining = btr; + int byteread = 0; + int retval=0; + + while (remaining>0) { + if (remaining < 256) + retval = fds[i].f.read(buffer, remaining); + else + retval = fds[i].f.read(buffer, 256); + if (retval>0) { + memcpy(buff,buffer,retval); + buff += retval; + byteread += retval; + remaining -= retval; + } + else { + break; + } + } + *br = byteread; + //emu_printi(byteread); + if (byteread <= 0) + return(FR_DISK_ERR); + else + return(FR_OK); +} + +FRESULT f_readn (FIL* fp, void* buff, unsigned int btr, unsigned int * br) +{ + return(f_read (fp, buff, btr, br)); +} + +FRESULT f_write (FIL* fp, const void* buff, unsigned int btw, unsigned int * bw) +{ + return(FR_OK); +} +FRESULT f_writen (FIL* fp, const void* buff, unsigned int btw, unsigned int * bw) +{ + return(FR_OK); +} +FRESULT f_lseek (FIL* fp, unsigned long ofs) +{ + int i = *fp; + //emu_printf("fseek"); + //emu_printi(ofs); + fds[i].f.seek(ofs); + return(FR_OK); +} + + +FRESULT f_unlink (const char * path) +{ + return(FR_OK); +} +FRESULT f_rename (const char * path_old, const char * path_new) +{ + return(FR_OK); +} +FRESULT f_stat (const char * path, FILINFO* fno) +{ + return(FR_OK); +} + +unsigned long f_tell (FIL * fp) +{ + int i = *fp; + emu_printf("ftell"); + return(fds[i].size); + //return(fds[i].f.ftell()); +} + +unsigned long f_size (FIL * fp) +{ + int i = *fp; + emu_printf("fsize"); + emu_printi(fds[i].size); + return(fds[i].size); +} + +FRESULT f_mkdir (const char* path) +{ + return(FR_OK); +} +#endif + + +/******************************** + * GFX wrapper +********************************/ +static unsigned short palette16[PALETTE_SIZE]; +static IntervalTimer myTimer; +volatile boolean vbl=true; +volatile boolean vgatimervsync=false; +static void (*vblCallback)(void) = nullptr; +static int skip=0; + +static void vblCount() { + if (vbl) { + vbl = false; + } else { + vbl = true; + } +} + +void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) +{ + if (index= MODE_VGA_320x240 ) { + if (vgatimervsync) { + while (vbl==vb) {}; + } + else { + tft.waitSync(); + } + } + else { + while (vbl==vb) {}; + } + if (vblCallback != nullptr) { + vblCallback(); + } +} + +void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride) +{ + if (skip == 0) { + tft.writeScreenPal(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); + } +} +void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLinePal(width,height,line, VBuf, palette16); + } +} + +void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine(width,height,line, VBuf); + } +} + +void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine8(width,height,line, VBuf, palette16); + } +} + +int emu_IsVga(void) +{ + return (tft.getMode() >= MODE_VGA_320x240?1:0); +} + +int emu_IsVgaHires(void) +{ + return (tft.getMode() >= MODE_VGA_640x240?1:0); +} + +int emu_FrameSkip(void) +{ + return skip; +} + + +/******************************** + * AUDIO wrapper +********************************/ +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +AudioPlaySystem mymixer; + +void emu_sndInit() { + Serial.println("sound init"); + mymixer.begin_audio(256, mymixer.snd_Mixer); + mymixer.start(); +} + +void emu_sndPlaySound(int chan, int volume, int freq) +{ + if (chan < 6) { + mymixer.sound(chan, freq, volume); + } + /* + Serial.print(chan); + Serial.print(":" ); + Serial.print(volume); + Serial.print(":" ); + Serial.println(freq); + */ +} + +void emu_sndPlayBuzz(int size, int val) { + mymixer.buzz(size,val); + //Serial.print((val==1)?1:0); + //Serial.print(":"); + //Serial.println(size); +} +#endif + +/******************************** + * Initialization +********************************/ +void emu_init(int hires) +{ + Serial.begin(115200); + vgahires = hires; + +#ifdef HAS_USB + myusb.begin(); +#ifdef HAS_USBKEY + keyboard1.attachPress(OnPress); + keyboard1.attachRelease(OnRelease); +#endif +#endif + +#ifdef FILEBROWSER + if (!SD.begin(SD_CS)) + { + Serial.println("No SD card detected"); + } + strcpy(selection,ROMSDIR); + FileHandlersInit(); + nbFiles = readNbFiles(); + Serial.println(nbFiles); +#endif + + emu_InitJoysticks(); +#ifdef SWAP_JOYSTICK + joySwapped = true; +#else + joySwapped = false; +#endif + + int keypressed = emu_ReadKeys(); +#ifdef HAS_T4_VGA + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } +#else + int gfx_mode = CFG_VGA; // default +#ifdef FILEBROWSER + gfx_mode = emu_readGfxConfig(); +#endif + // Force VGA if UP pressed + if (keypressed & MASK_JOY2_UP) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("VGA"); +#endif + gfx_mode = CFG_VGA; + } + else { + if (keypressed & MASK_JOY2_LEFT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ST"); +#endif + gfx_mode = CFG_ST; + } + else if (keypressed & MASK_JOY2_RIGHT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ILI"); +#endif + gfx_mode = CFG_ILI; + } + } + if (gfx_mode == CFG_VGA) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + else + { + tft.begin(gfx_mode == CFG_ILI?MODE_TFTILI_320x240:MODE_TFTST_320x240); + } +#endif + + if (keypressed & MASK_JOY2_DOWN) { + tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) ); + tft.drawTextNoDma(64,48, (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); +#ifdef FILEBROWSER + emu_eraseConfig(); + delay(1000); +#endif + } + else { +#ifdef FILEBROWSER + if (emu_readConfig()) { + autorun = true; + } +#endif + } + +#ifdef FILEBROWSER + toggleMenu(true); +#endif +} + + +void emu_start(int vblms, void * callback, int forcetimervsync) +{ + vgatimervsync = forcetimervsync?true:false; + tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); + tft.startRefresh(); + if (callback != nullptr) { + vblCallback = callback; + } + + myTimer.begin(vblCount, vblms); +#ifdef HAS_SND + emu_sndInit(); +#endif + usbnavpad = 0; +} diff --git a/MCUME_teensy41/teensyframework/emuapi.h b/MCUME_teensy41/teensyframework/emuapi.h new file mode 100644 index 0000000..5dd6130 --- /dev/null +++ b/MCUME_teensy41/teensyframework/emuapi.h @@ -0,0 +1,105 @@ +#ifndef EMUAPI_H +#define EMUAPI_H + +#include "platform_config.h" +#include "emucfg.h" + +#define ACTION_NONE 0 +#define ACTION_RUN1 1 +#define ACTION_RUN2 2 + +#define FORCE_VGATIMERVSYNC 1 +#define SUPPORT_HIRES 1 + +#define MASK_JOY2_RIGHT 0x0001 +#define MASK_JOY2_LEFT 0x0002 +#define MASK_JOY2_UP 0x0004 +#define MASK_JOY2_DOWN 0x0008 +#define MASK_JOY2_BTN 0x0010 +#define MASK_KEY_USER1 0x0020 +#define MASK_KEY_USER2 0x0040 +#define MASK_KEY_USER3 0x0080 +#define MASK_JOY1_RIGHT 0x0100 +#define MASK_JOY1_LEFT 0x0200 +#define MASK_JOY1_UP 0x0400 +#define MASK_JOY1_DOWN 0x0800 +#define MASK_JOY1_BTN 0x1000 +#define MASK_KEY_USER4 0x2000 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) + +#ifdef __cplusplus +extern "C" { +extern void emu_init(int hires=0); +extern void emu_start(int vblms, void * callback, int forcetimervsync=0); +#endif +extern void emu_printf(const char * text); +extern void emu_printi(int val); +extern void emu_printh(int val); +extern void * emu_Malloc(unsigned int size); +extern void * emu_MallocI(unsigned int size); +extern void emu_Free(void * pt); +extern void * emu_SMalloc(unsigned int size); +extern void emu_SFree(void * pt); + +extern int emu_FileOpen(const char * filepath, const char * mode); +extern int emu_FileRead(void * buf, int size, int handler); +extern int emu_FileWrite(void * buf, int size, int handler); +extern int emu_FileGetc(int handler); +extern int emu_FileSeek(int handler, int seek, int origin); +extern int emu_FileTell(int handler); +extern void emu_FileClose(int handler); + +extern unsigned int emu_FileSize(const char * filepath); +extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size); +extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek); + +extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index); +extern void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line); +extern void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride); +extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawVsync(void); +extern int emu_FrameSkip(void); +extern int emu_IsVga(void); +extern int emu_IsVgaHires(void); + +extern int menuActive(void); +extern char * menuSelection(void); +extern char * menuSecondSelection(void); +extern void toggleMenu(int on); +extern int handleMenu(unsigned short bClick); + +extern int handleOSKB(void); +extern void toggleOSKB(int forceon); + +extern void emu_InitJoysticks(void); +extern int emu_SwapJoysticks(int statusOnly); +extern unsigned short emu_DebounceLocalKeys(void); +extern int emu_ReadKeys(void); +extern int emu_GetPad(void); +extern int emu_GetMouse(int *x, int *y, int *buts); +extern int emu_MouseDetected(void); +extern int emu_GetJoystick(void); +extern int emu_KeyboardDetected(void); +extern int emu_ReadAnalogJoyX(int min, int max); +extern int emu_ReadAnalogJoyY(int min, int max); +extern int emu_ReadI2CKeyboard(void); +extern unsigned char emu_ReadI2CKeyboard2(int row); +extern void emu_KeyboardOnUp(int keymodifer, int key); +extern void emu_KeyboardOnDown(int keymodifer, int key); +extern void emu_MidiOnDataReceived(unsigned char data); + +extern void emu_sndPlaySound(int chan, int volume, int freq); +extern void emu_sndPlayBuzz(int size, int val); +extern void emu_sndInit(); +extern void emu_resetus(void); +extern int emu_us(void); + +extern int emu_setKeymap(int index); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/MCUME_teensy41/teensyframework/emucfg.h b/MCUME_teensy41/teensyframework/emucfg.h new file mode 100644 index 0000000..a0cce06 --- /dev/null +++ b/MCUME_teensy41/teensyframework/emucfg.h @@ -0,0 +1,115 @@ +#ifndef EMUCFG_H +#define EMUCFG_H + +#include "wrapemu.h" + +// Title: < > +#define TITLE " XXXX Emulator " +#define ROMSDIR "snes" + +#define emu_Init(ROM) { xxxx_Init(); xxxx_Start(ROM);} +#define emu_Step(x) { xxxx_Step(); } +#define emu_Input(x) { xxxx_Input(x); } + +#define MAX_FILENAME_PATH 64 +#define NB_FILE_HANDLER 4 + +#define PALETTE_SIZE 256 +#define VID_FRAME_SKIP 0x0 +#define TFT_VBUFFER_YCROP 0 +#define SINGLELINE_RENDERING 1 +#define CUSTOM_SND 1 +//#define TIMER_REND 1 +//#define EXTPAD 1 +#define EXTRA_HEAP 0x10 +#define FILEBROWSER 1 + + +#ifdef KEYMAP_PRESENT + +#define keylables_map0_0 (char *)"QWERTYUIOP\x1a" +#define keylables_map0_1 (char *)" ASDFGHJKL\x19" +#define keylables_map0_2 (char *)" ZXCVBNM,.;/" +#define keylables_map0_3 (char *)" +\x10-" +const unsigned short key_map0[] = { + 'q','w','E','R','T','Y','U','I','O','P',157, //default C64 uppercase always + 0,'A','S','D','F','G','H','J','K','L',10, + 0,'Z','X','C','V','B','N','M',',','.',';','/', + 0,0,0,0, + 0,'+',' ','-' + }; + +#define keylables_map1_0 (char *)"1234567890 " +#define keylables_map1_1 (char *)" " +#define keylables_map1_2 (char *)" " +#define keylables_map1_3 (char *)" " + +const unsigned short key_map1[] = { + '1','2','3','4','5','6','7','8','9','0',0, // digit keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map2_0 (char *)"!\"#$%^&*()@" +#define keylables_map2_1 (char *)" " +#define keylables_map2_2 (char *)" <>:?" +#define keylables_map2_3 (char *)" =\x10_" +const unsigned short key_map2[] = { + '!','"','#','$','%','^','&','*','(',')','@', // shiftothers + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 153,151,150,152, //U L R D + 0,'=',' ','_' + }; + +#define keylables_map3_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " +#define keylables_map3_1 (char *)" " +#define keylables_map3_2 (char *)" " +#define keylables_map3_3 (char *)" " + +const unsigned short key_map3[] = { + 129,130,131,132,133,134,135,136,0,0,0, // function keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map4_0 (char *)"QWERTYUIOP@" +#define keylables_map4_1 (char *)" ASDFGHJKL\x19" +#define keylables_map4_2 (char *)" ZXCVBNM<>:?" +#define keylables_map4_3 (char *)" =\x10_" +const unsigned short key_map4[] = { + 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase + 0,'A','S','D','F','G','H','J','K','L',10, + 0,'Z','X','C','V','B','N','M','<','>',':','?', + 0,0,0,0, + 0,'=',' ','_' + }; + +#define keylables_map5_0 (char *)" " +#define keylables_map5_1 (char *)" " +#define keylables_map5_2 (char *)" " +#define keylables_map5_3 (char *)" " + +const unsigned short key_map5[] = { + 0,0,0,0,0,0,0,0,0,0,0, // extra keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 153,151,150,152, //U L R D + 0,0,' ',0 + }; + +const unsigned short matkeys[] = { + 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 + 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 + 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 + 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN + 0x510,0x010,0x110,0x310, // row 4 + }; + +#endif + +#endif diff --git a/MCUME_teensy41/teensyframework/font8x8.h b/MCUME_teensy41/teensyframework/font8x8.h new file mode 100644 index 0000000..a0913e4 --- /dev/null +++ b/MCUME_teensy41/teensyframework/font8x8.h @@ -0,0 +1,148 @@ + +// Font: c64_lower.64c + +PROGMEM const unsigned char font8x8[128][8] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0000 (nul) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0001 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0002 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0003 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0004 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0005 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0006 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0007 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0008 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0009 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000A + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000B + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000C + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000D + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000E + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000F + + { 0x7f, 0x41, 0x41, 0x41, 0x41, 0x41, 0x7f, 0x00 }, // Space // 0x10 + { 0x00, 0x27, 0x31, 0x27, 0x21, 0x71, 0x00, 0x00 }, // F1 // 0x11 + { 0x00, 0x77, 0x41, 0x77, 0x11, 0x71, 0x00, 0x00 }, // F2 + { 0x00, 0x77, 0x41, 0x77, 0x41, 0x71, 0x00, 0x00 }, // F3 + { 0x00, 0x17, 0x51, 0x77, 0x41, 0x41, 0x00, 0x00 }, // F4 + { 0x00, 0x77, 0x11, 0x77, 0x41, 0x71, 0x00, 0x00 }, // F5 + { 0x00, 0x77, 0x11, 0x77, 0x51, 0x71, 0x00, 0x00 }, // F6 + { 0x00, 0x77, 0x41, 0x47, 0x41, 0x41, 0x00, 0x00 }, // F7 + { 0x00, 0x77, 0x51, 0x77, 0x51, 0x71, 0x00, 0x00 }, // F8 // 0x18 + { 0x00, 0x00, 0x20, 0x24, 0x3e, 0x04, 0x00, 0x00 }, // Return // 0x19 + { 0x00, 0x59, 0x4b, 0x5b, 0x4b, 0xd9, 0x00, 0x00 }, // Del // 0x1A + //{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0010 + //{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0011 + //{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0012 + //{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0013 + //{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0014 + //{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0015 + //{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0016 + //{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0017 + //{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0018 + //{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0019 + //{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001A + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001B + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001C + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001D + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001E + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001F + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 (space) + { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!) + { 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0022 (") + { 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // U+0023 (#) + { 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // U+0024 ($) + { 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // U+0025 (%) + { 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // U+0026 (&) + { 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0027 (') + { 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // U+0028 (() + { 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // U+0029 ()) + { 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // U+002A (*) + { 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // U+002B (+) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+002C (,) + { 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // U+002D (-) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+002E (.) + { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // U+002F (/) + { 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // U+0030 (0) + { 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // U+0031 (1) + { 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // U+0032 (2) + { 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // U+0033 (3) + { 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // U+0034 (4) + { 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // U+0035 (5) + { 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // U+0036 (6) + { 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // U+0037 (7) + { 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+0038 (8) + { 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // U+0039 (9) + { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+003A (:) + { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+003B (//) + { 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // U+003C (<) + { 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // U+003D (=) + { 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // U+003E (>) + { 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // U+003F (?) + { 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // U+0040 (@) + { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A) + { 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // U+0042 (B) + { 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // U+0043 (C) + { 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // U+0044 (D) + { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // U+0045 (E) + { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // U+0046 (F) + { 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // U+0047 (G) + { 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // U+0048 (H) + { 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0049 (I) + { 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // U+004A (J) + { 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // U+004B (K) + { 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // U+004C (L) + { 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // U+004D (M) + { 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // U+004E (N) + { 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // U+004F (O) + { 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // U+0050 (P) + { 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // U+0051 (Q) + { 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // U+0052 (R) + { 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // U+0053 (S) + { 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0054 (T) + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U+0055 (U) + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0056 (V) + { 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // U+0057 (W) + { 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // U+0058 (X) + { 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+0059 (Y) + { 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // U+005A (Z) + { 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // U+005B ([) + { 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // U+005C (\) + { 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // U+005D (]) + { 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // U+005E (^) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // U+005F (_) + { 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0060 (`) + { 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // U+0061 (a) + { 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // U+0062 (b) + { 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // U+0063 (c) + { 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // U+0064 (d) + { 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // U+0065 (e) + { 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // U+0066 (f) + { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0067 (g) + { 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // U+0068 (h) + { 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0069 (i) + { 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // U+006A (j) + { 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // U+006B (k) + { 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+006C (l) + { 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // U+006D (m) + { 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // U+006E (n) + { 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+006F (o) + { 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+0070 (p) + { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // U+0071 (q) + { 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // U+0072 (r) + { 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // U+0073 (s) + { 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // U+0074 (t) + { 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // U+0075 (u) + { 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0076 (v) + { 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // U+0077 (w) + { 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // U+0078 (x) + { 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0079 (y) + { 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // U+007A (z) + { 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // U+007B ({) + { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+007C (|) + { 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // U+007D (}) + { 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007E (~) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // U+007F +}; + + diff --git a/MCUME_teensy41/teensyframework/iopins.h b/MCUME_teensy41/teensyframework/iopins.h new file mode 100644 index 0000000..24bcda2 --- /dev/null +++ b/MCUME_teensy41/teensyframework/iopins.h @@ -0,0 +1,124 @@ +#ifndef IOPINS_H +#define IOPINS_H + +#include "platform_config.h" + +#ifdef TEECOMPUTER + +// Teecomputer layout + +// VGA +// R 3 2K +// R 4 1K +// R 33 500 +// G 11 2K +// G 13 1K +// G 2 500 +// B 10 820 +// B 12 390 +// HSYNC 15 82 +// VSYNC 8 82 + +// Display +#define TFT_SCLK 27 +#define TFT_MOSI 26 +#define TFT_MISO 255 +#define TFT_TOUCH_CS 255 +#define TFT_TOUCH_INT 255 +#define TFT_DC 23 +#define TFT_CS 22 // 255 for LORES ST7789 (NO CS) +#define TFT_RST 255 // 255 for ILI/ST if connected to 3.3V or 24 if really needed + + +// SD +#define SD_CS BUILTIN_SDCARD + +// Audio +#define AUDIO_I2S_DIN 7 +#define AUDIO_I2S_BCK 21 +#define AUDIO_I2S_LCK 20 + +// Keyboard matrix +#define KLED 14 +//Cols (out) +//pico 1,2,3,4,5,14 +//teen 16,6,24,25,28,31 +#define KCOLOUT1 16 +#define KCOLOUT2 6 +#define KCOLOUT3 24 +#define KCOLOUT4 25 +#define KCOLOUT5 28 +#define KCOLOUT6 31 +//Rows (in) +//pico 9,8,6,15,7,22 +//teen 19,18,17,5,29,30,32 //5,6,16,17,18,19 +#define KROWIN1 19 +#define KROWIN2 18 +#define KROWIN3 17 +#define KROWIN4 5 +#define KROWIN5 29 +#define KROWIN6 30 +#define KROWIN7 32 + +#define PIN_KEY_USER1 41 +#define PIN_KEY_USER2 40 + +// Second joystick (external) +#define PIN_JOY1_BTN 34 +#define PIN_JOY1_1 35 // UP +#define PIN_JOY1_2 36 // DOWN +#define PIN_JOY1_3 38 // RIGHT +#define PIN_JOY1_4 37 // LEFT + +#else + +// Original Layout +#define TFT_SCLK 13 +#define TFT_MOSI 11 +#define TFT_MISO 12 +#define TFT_TOUCH_CS 255 +#define TFT_TOUCH_INT 255 +#define TFT_DC 9 +#define TFT_CS 22 // 255 for LORES ST7789 (NO CS) +#define TFT_RST 23 // 255 for ILI/ST if connected to 3.3V + +// SD +#define SD_CS BUILTIN_SDCARD + +// I2C keyboard +#define I2C_SCL_IO 19 +#define I2C_SDA_IO 18 + +// Analog joystick (primary) for JOY2 and 5 extra buttons +#ifdef HAS_T4_VGA +#define PIN_JOY2_A1X A3 +#define PIN_JOY2_A2Y A2 +#define PIN_JOY2_BTN 14 +#define PIN_KEY_USER1 22 +#define PIN_KEY_USER2 23 + +// Second joystick +#define PIN_JOY1_BTN 34 +#define PIN_JOY1_1 35 // UP +#define PIN_JOY1_2 36 // DOWN +#define PIN_JOY1_3 38 // RIGHT +#define PIN_JOY1_4 37 // LEFT + +#else +#define PIN_JOY2_A1X A1 +#define PIN_JOY2_A2Y A2 +#define PIN_JOY2_BTN 17 +#define PIN_KEY_USER1 3 //34 +#define PIN_KEY_USER2 4 //35 + +// Second joystick +#define PIN_JOY1_BTN 2 +#define PIN_JOY1_1 14 // UP +#define PIN_JOY1_2 7 // DOWN +#define PIN_JOY1_3 6 // RIGHT +#define PIN_JOY1_4 5 // LEFT +#endif + +#endif + +#endif diff --git a/MCUME_teensy41/teensyframework/platform_config.h b/MCUME_teensy41/teensyframework/platform_config.h new file mode 100644 index 0000000..8eb6c92 --- /dev/null +++ b/MCUME_teensy41/teensyframework/platform_config.h @@ -0,0 +1,47 @@ +#ifndef _PLATFORM_CONFIG_H_ +#define _PLATFORM_CONFIG_H_ + +#define TEECOMPUTER 1 + +#ifdef TEECOMPUTER +#define TFTSPI1 1 +//#define HAS_T4_VGA 1 +#define HAS_SND 1 +#define HAS_USB 1 +//#define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 +//#define HAS_USBJOY 1 // not working yet +#define PT8211 1 + +#else + +#define HAS_T4_VGA 1 +//#define INVX 1 +#define INVY 1 +#define HAS_USB 1 +//#define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 +//#define HAS_USBJOY 1 // not working yet +#define PT8211 1 + +#endif + + +//#define FLIP_SCREEN 1 +//#define ILI9341 1 +//#define ST7789 1 +//#define SWAP_JOYSTICK 1 +//#define LOHRES 1 +//#define ROTATE_SCREEN 1 +//#define EXTERNAL_SD 1 + + +//#define USE_SDFAT 1 +//#define SD_FAT_TYPE 1 +//#define USE_SDFS 1 +//#define SDFSDEV "1:" + + +#endif diff --git a/MCUME_teensy41/teensyframework/t4_dsp.cpp b/MCUME_teensy41/teensyframework/t4_dsp.cpp new file mode 100644 index 0000000..43301fa --- /dev/null +++ b/MCUME_teensy41/teensyframework/t4_dsp.cpp @@ -0,0 +1,1774 @@ +/* + TFT/VGA driver + DMA TFT driver based on C64 ILI9341 dma driver from Frank Bösing, 2017 +*/ + +#include "T4_DSP.h" + +#include +#include + +#include "font8x8.h" + +// TFT constants and variables +#define TFT_LINEARINT 1 +#define LINEARINT_HACK 1 +#define DMA_LINES_PER_BLOCK 64 +#define DMA_NUM_SETTINGS 4 + +#define TFT_SWRESET 0x01 +#define TFT_SLPOUT 0x11 +#define TFT_INVON 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_MADCTL 0x36 +#define TFT_PIXFMT 0x3A +#define TFT_MADCTL_MY 0x80 +#define TFT_MADCTL_MX 0x40 +#define TFT_MADCTL_MV 0x20 +#define TFT_MADCTL_ML 0x10 +#define TFT_MADCTL_RGB 0x00 +#define TFT_MADCTL_BGR 0x08 +#define TFT_MADCTL_MH 0x04 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) +//#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) +//#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) +//#define R16(rgb) ((rgb>>8)&0xf8) +//#define G16(rgb) ((rgb>>3)&0xfc) +//#define B16(rgb) ((rgb<<3)&0xf8) + +// LPSPI4 = SPI0 in Teensy 4.0 +// LPSPI3 = SPI1 in Teensy 4.0 +// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) + +#ifdef TFTSPI1 +#define SPI SPI1 +#define LPSPIP_TDR LPSPI3_TDR +#define LPSPIP_CR LPSPI3_CR +#define LPSPIP_CFGR1 LPSPI3_CFGR1 +#define LPSPIP_TCR LPSPI3_TCR +#define LPSPIP_DER LPSPI3_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX +#else +#define LPSPIP_TDR LPSPI4_TDR +#define LPSPIP_CR LPSPI4_CR +#define LPSPIP_CFGR1 LPSPI4_CFGR1 +#define LPSPIP_TCR LPSPI4_TCR +#define LPSPIP_DER LPSPI4_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX +#endif + +#define SPICLOCK 60000000 +#define SPI_MODE SPI_MODE0 + +// VGA constants and macros +typedef uint8_t vga_pixel; +#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) + +static DMASetting dmasettings[DMA_NUM_SETTINGS]; +static DMAChannel dmatx; +static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K +static volatile uint8_t rstop = 0; +static volatile bool cancelled = false; +static volatile uint8_t curTransfer = 0; +static uint8_t nbTransfer = 0; +static uint16_t * tft_buffer; +static int tft_width; +static int tft_height; +static int tft_stride; + +#define DELAY_MASK 0x80 +PROGMEM static const uint8_t init_commands[] = { + 1+DELAY_MASK, TFT_SWRESET, 150, + 1+DELAY_MASK, TFT_SLPOUT, 255, + 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, + 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, + 1, TFT_INVON, + 1, TFT_DISPON, + 0 +}; + +// VGA constants and variables +// Objective: +// generates VGA signal fully in hardware with as little as possible CPU help + +// Principle: +// QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) +// 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate +// RGB out, combined to create 8bits(/12bits) output. + +// Note: +// - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels +// - experimental resolution: 352x240,352x480 +// - experimental resolution: 512x240,512x480 (not stable) +// - video memory is allocated using malloc in T4 heap +// - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing +// but tried to be compensated by pixel shifting +// - Default is 8bits RRRGGGBB (332) +// But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! +// - Only ok at 600MHz else some disturbances visible + + + +#define TOP_BORDER 40 +#define PIN_HBLANK 15 + +#define PIN_R_B2 33 +#define PIN_R_B1 4 +#define PIN_R_B0 3 +#define PIN_G_B2 2 +#define PIN_G_B1 13 +#define PIN_G_B0 11 +#define PIN_B_B1 12 +#define PIN_B_B0 10 + + +#define DMA_HACK 0x80 + +#define R16(rgb) ((rgb>>8)&0xf8) +#define G16(rgb) ((rgb>>3)&0xfc) +#define B16(rgb) ((rgb<<3)&0xf8) + +// VGA 640x480@60Hz +// Screen refresh rate 60 Hz +// Vertical refresh 31.46875 kHz +// Pixel freq. 25.175 MHz +// +// Visible area 640 25.422045680238 us +// Front porch 16 0.63555114200596 us +// Sync pulse 96 3.8133068520357 us +// Back porch 48 1.9066534260179 us +// Whole line 800 31.777557100298 us + +#define frame_freq 60.0 // Hz +#define line_freq 31.46875 // KHz +#define pix_freq (line_freq*800) // KHz (25.175 MHz) + +// pix_period = 39.7ns +// H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) +#define frontporch_pix 20 //16 +#define backporch_pix 44 //48 + +// Flexio Clock +// PLL3 SW CLOCK (3) => 480 MHz +// PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) +#define FLEXIO_CLK_SEL_PLL3 3 +#define FLEXIO_CLK_SEL_PLL5 2 + +/* Set video PLL */ +// There are /1, /2, /4, /8, /16 post dividers for the Video PLL. +// The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, +// and CCM_ANALOG_MISC2 register sets according to the following equation. +// PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + +// nfact: +// This field controls the PLL loop divider. +// Valid range for DIV_SELECT divider value: 27~54. + +#define POST_DIV_SELECT 2 + +// Full buffer including back/front porch +static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; +static uint32_t dstbuffer __attribute__((aligned(32))); + +// Visible vuffer +static vga_pixel * vga_buffer; +static int vga_width; +static int vga_height; +static int vga_stride; + +static int maxpixperline; +static int left_border; +static int right_border; +static int line_double; +static int pix_shift; +static int ref_div_select; +static int ref_freq_num; +static int ref_freq_denom; +static int ref_pix_shift; +static int combine_shiftreg; + +#ifdef DEBUG +static uint32_t ISRTicks_prev = 0; +volatile uint32_t ISRTicks = 0; +#endif + +uint8_t T4_DSP::_rst; +uint8_t T4_DSP::_cs; +uint8_t T4_DSP::_dc; +uint8_t T4_DSP::_mosi; +uint8_t T4_DSP::_sclk; +uint8_t T4_DSP::_vsync_pin = -1; +DMAChannel T4_DSP::flexio1DMA; +DMAChannel T4_DSP::flexio2DMA; + +static volatile uint32_t VSYNC = 0; +static volatile uint32_t currentLine=0; +#define NOP asm volatile("nop\n\t"); +static gfx_mode_t gfxmode = MODE_UNDEFINED; + + +FASTRUN void T4_DSP::TFT_isr(void) { + dmatx.clearInterrupt(); + curTransfer++; + if (curTransfer >= nbTransfer) { + curTransfer = 0; + if (cancelled) { + dmatx.disable(); + rstop = 1; + } + } + arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); +} + +FASTRUN void T4_DSP::QT3_isr(void) { + TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); + TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); + + cli(); + + // V-PULSE + if (currentLine > 0) { + digitalWrite(_vsync_pin, 1); + VSYNC = 0; + } else { + digitalWrite(_vsync_pin, 0); + VSYNC = 1; + } + + currentLine++; + currentLine = currentLine % 525; + + + uint32_t y = (currentLine - TOP_BORDER) >> line_double; + // Visible area + + if (y >= 0 && y < vga_height) { + // Disable DMAs + //DMA_CERQ = flexio2DMA.channel; + //DMA_CERQ = flexio1DMA.channel; + + // Setup source adress + // Aligned 32 bits copy + unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; + flexio2DMA.TCD->SADDR = p; + if (pix_shift & DMA_HACK) + { + // Unaligned copy + uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; + flexio1DMA.TCD->SADDR = p2; + } + else { + p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 + flexio1DMA.TCD->SADDR = p; + } + + // Enable DMAs + //flexio2DMA.enable(); + //flexio1DMA.enable(); + DMA_SERQ = flexio2DMA.channel; + DMA_SERQ = flexio1DMA.channel; + arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); + } + sei(); + +#ifdef DEBUG + ISRTicks++; +#endif + asm volatile("dsb"); +} + +static void setDmaStruct() { + uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; + uint16_t * fb = (uint16_t*)malloc(remaining); + tft_buffer = fb; + tft_width = TFT_WIDTH; + tft_height = TFT_HEIGHT; + tft_stride = TFT_WIDTH; + uint16_t col=RGBVAL16(0x00,0x00,0x00); + int i=0; + while (remaining > 0) { + int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); + blocks[i] = fb; + for (int j=0;jATTR_DST = 1; + dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); + dmasettings[i].interruptAtCompletion(); + fb += len/2; + remaining -= len; + i++; + } + dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); + nbTransfer = i; +} + +static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 +{ +//if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; + CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE + | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 + | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); + CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; + CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock + const int div_post_pll = 1; // other values: 2,4 + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass +} + +T4_DSP::T4_DSP() +{ + _cs = TFT_CS; + _dc = TFT_DC; + _rst = TFT_RST; + _mosi = TFT_MOSI; + _sclk = TFT_SCLK; + pinMode(_dc, OUTPUT); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, 1); + digitalWrite(_dc, 1); + _vsync_pin = 8; +} + + +void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { + int dx=0; + int dy=0; + digitalWrite(_dc, 0); + SPI.transfer(TFT_CASET); + digitalWrite(_dc, 1); + SPI.transfer16(x1+dx); + digitalWrite(_dc, 1); + SPI.transfer16(x2+dx); + digitalWrite(_dc, 0); + SPI.transfer(TFT_PASET); + digitalWrite(_dc, 1); + SPI.transfer16(y1+dy); + digitalWrite(_dc, 1); + SPI.transfer16(y2+dy); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + return; +} + +void T4_DSP::tft_setup(bool isST) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + // RESET if reset pin defined + if (_rst != 0xff) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + const uint8_t *addr = init_commands; + uint8_t count; + digitalWrite(_cs, 0); + while (count = *addr++) { + uint8_t command = *addr++; + if ( (command == TFT_INVON) && (!isST) ) { + // Skip TFT_INVON for ILI + } + else { + digitalWrite(_dc, 0); // command + SPI.transfer(command); + uint16_t ms = count & DELAY_MASK; + count &= ~DELAY_MASK; + while (--count > 0) { // data + uint8_t data = *addr++; + if ( (command == TFT_MADCTL) && (isST) ) { + data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; + } + digitalWrite(_dc, 1); + SPI.transfer(data); + } + if (ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + digitalWrite(_cs, 1); + SPI.endTransaction(); + delay(2); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + } + } + } + digitalWrite(_cs, 1); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + SPI.endTransaction(); + /* + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_dc, 0); + digitalWrite(_cs, 0); + SPI.transfer(TFT_MADCTL); + digitalWrite(_dc, 1); + SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); + // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); + digitalWrite(_cs, 1); + SPI.endTransaction(); + */ + cancelled = false; +} + +// display VGA image +gfx_error_t T4_DSP::begin(gfx_mode_t mode) +{ + uint32_t flexio_clock_div; + combine_shiftreg = 0; +// int div_select = 49; +// int num = 135; +// int denom = 100; + int div_select = 20; + int num = 9800; + int denom = 10000; + int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; + int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; + set_videoClock(div_select,num,denom,true); + +#ifdef DEBUG + Serial.println(mode); + Serial.println("mode"); +#endif + + switch(mode) + { + case MODE_TFTILI_320x240: +#ifdef DEBUG + Serial.println("TFTILI_320x240"); +#endif + tft_setup(false); + gfxmode = mode; + break; + case MODE_TFTST_320x240: +#ifdef DEBUG + Serial.println("TFTST_320x240"); +#endif + tft_setup(true); + gfxmode = mode; + break; + + case MODE_VGA_320x240: +#ifdef DEBUG + Serial.println("VGA_320x240"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_320x480: +#ifdef DEBUG + Serial.println("VGA_320x480"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_640x240: +#ifdef DEBUG + Serial.println("VGA_640x240"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/pix_freq; + line_double = 1; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_640x480: +#ifdef DEBUG + Serial.println("VGA_640x480"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = (flexio_freq/pix_freq); + line_double = 0; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_512x240: +#ifdef DEBUG + Serial.println("VGA_512x240"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 1; + pix_shift = 0; + break; + + case MODE_VGA_512x480: +#ifdef DEBUG + Serial.println("VGA_512x480"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 0; + pix_shift = 0; + break; + + case MODE_VGA_352x240: +#ifdef DEBUG + Serial.println("VGA_352x240"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_352x480: +#ifdef DEBUG + Serial.println("VGA_352x480"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + } + + if (mode >= MODE_VGA_320x240) + { + if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { + fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); + digitalWrite(_cs, 0); + digitalWrite(_dc, 0); + SPI.transfer(TFT_DISPOFF); + digitalWrite(_cs, 1); + delay(20); + digitalWrite(_cs, 0); + digitalWrite(_cs, 1); + } + gfxmode = mode; + + maxpixperline = vga_stride; + // Save param for tweek adjustment + ref_div_select = div_select; + ref_freq_num = num; + ref_freq_denom = denom; + ref_pix_shift = pix_shift; + +#ifdef DEBUG + Serial.println("frequency"); + Serial.println(flexio_freq); + Serial.println("div"); + Serial.println(flexio_freq/pix_freq); +#endif + + pinMode(_vsync_pin, OUTPUT); + pinMode(PIN_HBLANK, OUTPUT); + + /* Basic pin setup FlexIO1 */ + pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 + pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 + pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 + pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 + /* Basic pin setup FlexIO2 */ + pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 + pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 + pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 + pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 + + /* High speed and drive strength configuration */ + *(portControlRegister(PIN_G_B2)) = 0xFF; + *(portControlRegister(PIN_R_B0)) = 0xFF; + *(portControlRegister(PIN_R_B1)) = 0xFF; + *(portControlRegister(PIN_R_B2)) = 0xFF; + *(portControlRegister(PIN_B_B0)) = 0xFF; + *(portControlRegister(PIN_B_B1)) = 0xFF; + *(portControlRegister(PIN_G_B0)) = 0xFF; + *(portControlRegister(PIN_G_B1)) = 0xFF; + + /* Set clock for FlexIO1 and FlexIO2 */ + CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) + | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); + CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) + | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); + + + /* Set up pin mux FlexIO1 */ + *(portConfigRegister(PIN_G_B2)) = 0x14; + *(portConfigRegister(PIN_R_B0)) = 0x14; + *(portConfigRegister(PIN_R_B1)) = 0x14; + *(portConfigRegister(PIN_R_B2)) = 0x14; + /* Set up pin mux FlexIO2 */ + *(portConfigRegister(PIN_B_B0)) = 0x14; + *(portConfigRegister(PIN_B_B1)) = 0x14; + *(portConfigRegister(PIN_G_B0)) = 0x14; + *(portConfigRegister(PIN_G_B1)) = 0x14; + + /* Enable the clock */ + CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + /* Enable the FlexIO with fast access */ + FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + + uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; + uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; + + /* Shifter 0 registers for FlexIO2 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 + inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter + stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled + startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable + timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 + timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock + pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output + pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity + shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode + /* Shifter 0 registers for FlexIO1 */ + FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + /* Shifter 0 registers for FlexIO1 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 + FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + if (combine_shiftreg) { + pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled + FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + } + /* Timer 0 registers for FlexIO2 */ + timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset + timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output + timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset + timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare + timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert + stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled + startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled + if (combine_shiftreg) { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag + } + else { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag + } + triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low + triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected + pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled + //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 + //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high + timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode + // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) + + int shifts_per_transfer; + if (combine_shiftreg) { + shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 + } + else { + shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 + } + FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); + /* Timer 0 registers for FlexIO1 */ + FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); +#ifdef DEBUG + Serial.println("FlexIO setup complete"); +#endif + + /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ + if (combine_shiftreg) { + FLEXIO2_SHIFTSDEN |= (1<<1); + FLEXIO1_SHIFTSDEN |= (1<<1); + } + else { + FLEXIO2_SHIFTSDEN |= (1<<0); + FLEXIO1_SHIFTSDEN |= (1<<0); + } + /* Disable DMA channel so it doesn't start transferring yet */ + flexio1DMA.disable(); + flexio2DMA.disable(); + /* Set up DMA channel to use Shifter 0 trigger */ + flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); + flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); + + + if (combine_shiftreg) { + flexio2DMA.TCD->NBYTES = 8; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 8; + flexio2DMA.TCD->CITER = maxpixperline / 8; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + flexio1DMA.TCD->NBYTES = 8; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 8; + flexio1DMA.TCD->CITER = maxpixperline / 8; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Setup DMA2 Flexio2 copy + flexio2DMA.TCD->NBYTES = 4; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 4; + flexio2DMA.TCD->CITER = maxpixperline / 4; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + // Setup DMA1 Flexio1 copy + // Use pixel shift to avoid color smearing? + if (pix_shift & DMA_HACK) + { + if (pix_shift & 0x3 == 0) { + // Aligned 32 bits copy (32bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Unaligned (source) 32 bits copy (8bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 1; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion + } + } + else + { + // Aligned 32 bits copy + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + } + +#ifdef DEBUG + Serial.println("DMA setup complete"); +#endif + + // enable clocks for QTIMER3: generates the 15KHz for hsync + // Pulse: + // low : 3.8133 us => 569x6.7ns + // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) + // (OLD TEST) + // (4us low, 28us high => 32us) + // (597x6.7ns for 4us) + // (4179x6.7ns for 28us) + CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 + //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 + + #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz + #define MARGIN_D 1000 + + TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer + // Invert output pin as we want the interupt on rising edge + TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) + TMR3_CNTR3 = 0; + TMR3_LOAD3 = 0; + + /* Inverted timings */ + unsigned long long cpu_freq = F_CPU; + unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; + int rate2 = rate; + + int substract = 1; + if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { + substract=5; + rate2=1652; + } + + #ifdef DEBUG + Serial.print("MARGIN_N is: "); + Serial.println(rate2, DEC); + Serial.print("SUBSTRACT is: "); + Serial.println(substract, DEC); +#endif + TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; + TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; + /* + TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; + */ + TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on + TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), + // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) + //configure Teensy pin Compare output + IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 + attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function + NVIC_ENABLE_IRQ(IRQ_QTIMER3); +#ifdef DEBUG + Serial.println("QTIMER3 setup complete"); + Serial.print("V-PIN is "); + Serial.println(_vsync_pin); +#endif + + /* initialize gfx buffer */ + if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift + if (gfxbuffer == NULL) return(GFX_ERROR); +#ifdef DEBUG + Serial.println("Memory allocated"); +#endif + + memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); + vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; +#ifdef DEBUG + Serial.println(vga_stride); + Serial.println(vga_height); + Serial.println("Screen cleared"); +#endif + } + + return(GFX_OK); +} + +gfx_mode_t T4_DSP::getMode(void) +{ + return gfxmode; +} + +void T4_DSP::startRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + curTransfer = 0; + rstop = 0; + //dmatx.begin(true); + dmatx.attachInterrupt(TFT_isr); + setDmaStruct(); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + + digitalWrite(_cs, HIGH); + SPI.begin(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + + LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: + LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX + LPSPIP_TCR = 15; // Framesize 16 Bits + //LPSPIP_FCR = 0; // Fifo Watermark + LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable + LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: + dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); + + dmatx = dmasettings[0]; + digitalWrite(_cs, 0); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + dmatx.enable(); + } +} + + +void T4_DSP::stopRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + rstop = 1; + unsigned long m = millis(); + cancelled = true; + while (!rstop) { + if ((millis() - m) > 100) break; + delay(10); + asm volatile("wfi"); + }; + rstop = 0; + delay(50); + cancelled = false; + dmatx.detachInterrupt(); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + SPI.end(); +#ifdef ST7789 +// begin(gfxmode); +#endif + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + } +} + +int T4_DSP::get_frame_buffer_size(int *width, int *height) { + if (gfxmode < MODE_VGA_320x240) { + if (width != nullptr) *width = tft_width; + if (height != nullptr) *height = tft_height; + return tft_stride; + } + else { + if (width != nullptr) *width = vga_width; + if (height != nullptr) *height = vga_height; + return vga_stride; + } +} + +void T4_DSP::waitSync() +{ + if (gfxmode >= MODE_VGA_320x240) { + while (VSYNC == 0) {}; + } +} + +void T4_DSP::waitLine(int line) +{ + if (gfxmode >= MODE_VGA_320x240) { + while (currentLine != line) {}; + } +} + +/*********************************************************************************************** + No DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreenNoDma(uint16_t color) { + if (gfxmode < MODE_VGA_320x240) { + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + int i,j; + for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(arx, ary, arx+arw-1, ary+arh-1); + bitmap = bitmap + bmp_offy*w + bmp_offx; + for (int row=0;row> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + bits = *charpt++; + //digitalWrite(_dc, 1); + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + x +=8; + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + else { + drawText(x, y, text, fgcolor, bgcolor, doublesize); + } +} + + +/*********************************************************************************************** + DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreen(uint16_t color) { + int i,j; + if (gfxmode < MODE_VGA_320x240) { + for (j=0; j> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + dst=&tft_buffer[l*tft_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + x +=8; + } + } + else { + vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); + vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); + vga_pixel * dst; + while ((c = *text++)) { + const unsigned char * charpt=&font8x8[c][0]; + int l=y; + for (int i=0;i<8;i++) + { + unsigned char bits; + if (doublesize) { + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + x +=8; + } + } +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { + drawSprite(x,y,bitmap, 0,0,0,0); +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) +{ + int bmp_offx = 0; + int bmp_offy = 0; + uint16_t *bmp_ptr; + int w =*bitmap++; + int h = *bitmap++; + if ( (arw == 0) || (arh == 0) ) { + // no crop window + arx = x; + ary = y; + arw = w; + arh = h; + } + else { + if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + int l=ary; + bitmap = bitmap + bmp_offy*w + bmp_offx; + + if (gfxmode < MODE_VGA_320x240) { + for (int row=0;row tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]; + pos +=step; + } + #endif + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i 2) ) y += (tft_height-height)/2; + uint16_t * dst=&tft_buffer[y*tft_stride]; + if (width > tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]]; + pos +=step; + } +#endif + } + else if ((width*2) == tft_width) { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]]; + *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i tft_width) { + int step = ((width << 8)/tft_width); + int pos = 0; + for (int i=0; i> 8]]; + pos +=step; + } + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = pix; + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i +#include +#endif + +#include "platform_config.h" +#include "iopins.h" + + + +#ifndef TFT_WIDTH +#define TFT_WIDTH 320 +#endif +#define TFT_REALWIDTH 320 + +#ifndef TFT_HEIGHT +#define TFT_HEIGHT 240 +#endif +#define TFT_REALHEIGHT 240 + + +typedef enum gfx_mode_t +{ + MODE_UNDEFINED = 0, + MODE_TFTILI_320x240 = 1, + MODE_TFTST_320x240 = 2, + MODE_VGA_320x240 = 3, + MODE_VGA_320x480 = 4, + MODE_VGA_352x240 = 5, + MODE_VGA_352x480 = 6, + MODE_VGA_512x240 = 7, + MODE_VGA_512x480 = 8, + MODE_VGA_640x240 = 9, + MODE_VGA_640x480 = 10 +} gfx_mode_t; + +typedef enum gfx_error_t +{ + GFX_OK = 0, + GFX_ERROR = -1 +} gfx_error_t; + + +#ifdef __cplusplus + +class T4_DSP +{ + public: + T4_DSP(); + + gfx_error_t begin(gfx_mode_t mode); + gfx_mode_t getMode(void); + void startRefresh(void); + void stopRefresh(); + + int get_frame_buffer_size(int *width, int *height); + void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); + + // wait next Vsync + void waitSync(); + void waitLine(int line); + + // NoDMA functions + void fillScreenNoDma(uint16_t color); + void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + // DMA functions + void fillScreen(uint16_t color); + void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + void writeLine(int width, int height, int y, uint16_t *buf); + void writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + void writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16); + void writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + + protected: + static uint8_t _rst, _cs, _dc; + static uint8_t _mosi, _sclk; + static uint8_t _vsync_pin; + static DMAChannel flexio1DMA; + static DMAChannel flexio2DMA; + void tft_setup(bool isST); + static void TFT_isr(void); + static void QT3_isr(void); +}; + +#endif +#endif diff --git a/MCUME_teensy41/teensyframework/teensyframework.ino b/MCUME_teensy41/teensyframework/teensyframework.ino new file mode 100644 index 0000000..658e84b --- /dev/null +++ b/MCUME_teensy41/teensyframework/teensyframework.ino @@ -0,0 +1,45 @@ +extern "C" { + #include "emuapi.h" + #include "iopins.h" +} + +#include "t4_dsp.h" +extern T4_DSP tft; + +// **************************************************** +// the setup() method runs once, when the sketch starts +// **************************************************** +void setup() { + emu_init(); +} + +static unsigned char col = 0; +// **************************************************** +// the loop() method runs continuously +// **************************************************** +void loop(void) +{ + char * filename; +#ifdef FILEBROWSER + while (true) { + if (menuActive()) { + uint16_t bClick = emu_DebounceLocalKeys(); + int action = handleMenu(bClick); + filename = menuSelection(); + if (action == ACTION_RUN1) { + break; + } + delay(20); + } + } +#endif + emu_start(20000,nullptr); + emu_Init(filename); + while (true) { + uint16_t bClick = emu_DebounceLocalKeys(); + emu_Input(bClick); + emu_Step(); + tft.fillScreen(RGBVAL16(col++,0x00,0x00)); + emu_DrawVsync(); + } +} diff --git a/MCUME_teensy41/teensyframework/wrapemu.cpp b/MCUME_teensy41/teensyframework/wrapemu.cpp new file mode 100644 index 0000000..523c817 --- /dev/null +++ b/MCUME_teensy41/teensyframework/wrapemu.cpp @@ -0,0 +1,126 @@ +#include +#include + +extern "C" { +#include "emuapi.h" +#include "platform_config.h" +} +#include + + +// Emulation includes + + +static int ik; // joypad key +static int pik=0; + +static int ihk; // I2C keyboard key +static int iusbhk; // USB keyboard key + +void xxxx_Input(int bClick) { + ik = emu_GetPad(); + ihk = emu_ReadI2CKeyboard(); +} + +void emu_KeyboardOnDown(int keymodifer, int key) { + int keyCode = -1; //INV_KEY; + if ((key >=0xc0) && (key <=0xdf)) { + keyCode = ((key-0xc0) & 0x1f) + 0x7f; + } + else { + keyCode = key & 0x7f; + } + + //Serial.println(keyCode); + + if (keyCode != -1) { + iusbhk = keyCode; + } +} + +void emu_KeyboardOnUp(int keymodifer, int key) { + iusbhk = 0; +} + +void xxxx_Init(void) +{ +#ifdef HAS_SND + emu_sndInit(); +#endif +} + + +void xxxx_Start(char * filename) +{ + emu_printf("emu starting"); + + emu_printf("emu started"); +} + +static int prev_hk = 0; +void xxxx_Step(void) +{ + int k=ik; +#ifdef TEECOMPUTER + int hk = ihk; + if (hk == 'q') { // SELECT + //emu_printf("selectd"); + } + else if (hk == 'w') { // START + //emu_printf("startd"); + } + else { + if (prev_hk == 'q') { + //emu_printf("selectu"); + } + else if (prev_hk == 'w') { + //emu_printf("startu"); + } + } + prev_hk = hk; + // Ignore joypad if shift/fn is pressed!!! + //if ( !(k & MASK_KEY_USER1) && !(k & MASK_KEY_USER2) ) +#endif + { + if ( ( !(pik & MASK_JOY2_BTN) && (k & MASK_JOY2_BTN) ) || ( !(pik & MASK_JOY1_BTN) && (k & MASK_JOY1_BTN) ) ) { + + } + else if ( ( (pik & MASK_JOY2_BTN) && !(k & MASK_JOY2_BTN) ) || ( (pik & MASK_JOY1_BTN) && !(k & MASK_JOY1_BTN) ) ) { + + } + if ( ( !(pik & MASK_JOY2_UP) && (k & MASK_JOY2_UP) ) || ( !(pik & MASK_JOY1_UP) && (k & MASK_JOY1_UP) ) ) { + + } + else if ( ( (pik & MASK_JOY2_UP) && !(k & MASK_JOY2_UP) ) || ( (pik & MASK_JOY1_UP) && !(k & MASK_JOY1_UP) ) ) { + + } + if ( ( !(pik & MASK_JOY2_DOWN) && (k & MASK_JOY2_DOWN) ) || ( !(pik & MASK_JOY1_DOWN) && (k & MASK_JOY1_DOWN) ) ) { + + } + else if ( ( (pik & MASK_JOY2_DOWN) && !(k & MASK_JOY2_DOWN) ) || ( (pik & MASK_JOY1_DOWN) && !(k & MASK_JOY1_DOWN) ) ) { + + } + if ( ( !(pik & MASK_JOY2_RIGHT) && (k & MASK_JOY2_RIGHT) ) || ( !(pik & MASK_JOY1_RIGHT) && (k & MASK_JOY1_RIGHT) ) ) { + + } + else if ( ( (pik & MASK_JOY2_RIGHT) && !(k & MASK_JOY2_RIGHT) ) || ( (pik & MASK_JOY1_RIGHT) && !(k & MASK_JOY1_RIGHT) ) ) { + + } + if ( ( !(pik & MASK_JOY2_LEFT) && (k & MASK_JOY2_LEFT) ) || ( !(pik & MASK_JOY1_LEFT) && (k & MASK_JOY1_LEFT) ) ) { + + } + else if ( ( (pik & MASK_JOY2_LEFT) && !(k & MASK_JOY2_LEFT) ) || ( (pik & MASK_JOY1_LEFT) && !(k & MASK_JOY1_LEFT) ) ) { + + } + } + + pik = k; + +} + +#ifdef HAS_SND +void SND_Process( void * stream, int len ) +{ +} +#endif + diff --git a/MCUME_teensy41/teensyframework/wrapemu.h b/MCUME_teensy41/teensyframework/wrapemu.h new file mode 100644 index 0000000..34916ed --- /dev/null +++ b/MCUME_teensy41/teensyframework/wrapemu.h @@ -0,0 +1,4 @@ +extern void xxxx_Init(void); +extern void xxxx_Step(void); +extern void xxxx_Start(char * filename); +extern void xxxx_Input(int key); diff --git a/MCUME_teensy41/teensygen/emuapi.cpp b/MCUME_teensy41/teensygen/emuapi.cpp index c367cb0..e128cca 100644 --- a/MCUME_teensy41/teensygen/emuapi.cpp +++ b/MCUME_teensy41/teensygen/emuapi.cpp @@ -5,25 +5,31 @@ extern "C" { #include "iopins.h" } -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#else -#include "tft_t_dma.h" -#endif +#include -#ifdef HAS_USBKEY +#ifdef HAS_USB #include "USBHost_t36.h" // Read this header first for key info USBHost myusb; USBHub hub1(myusb); +#ifdef HAS_USBKEY KeyboardController keyboard1(myusb); USBHIDParser hid1(myusb); MouseController mouse1(myusb); +#endif +#ifdef HAS_USBMIDI MIDIDevice midi1(myusb); #endif +#ifdef HAS_USBJOY +#define COUNT_JOYSTICKS 4 +JoystickController joysticks[COUNT_JOYSTICKS](myusb); +#endif +#endif static bool emu_writeConfig(void); static bool emu_readConfig(void); static bool emu_eraseConfig(void); +static bool emu_writeGfxConfig(char * display_type); +static int emu_readGfxConfig(void); static bool mouseDetected = false; static bool keyboardDetected = false; @@ -34,12 +40,13 @@ static File file; #define MAX_FILES 64 #define AUTORUN_FILENAME "autorun.txt" +#define GFX_CFG_FILENAME "gfxmode.txt" -#define MAX_FILENAME_SIZE 24 +#define MAX_FILENAME_SIZE 34 #define MAX_MENULINES 9 #define TEXT_HEIGHT 16 #define TEXT_WIDTH 8 -#define MENU_FILE_XOFFSET (6*TEXT_WIDTH) +#define MENU_FILE_XOFFSET (2*TEXT_WIDTH) #define MENU_FILE_YOFFSET (2*TEXT_HEIGHT) #define MENU_FILE_W (MAX_FILENAME_SIZE*TEXT_WIDTH) #define MENU_FILE_H (MAX_MENULINES*TEXT_HEIGHT) @@ -53,7 +60,8 @@ static File file; #define MENU_VGA_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) #define MENU_VGA_YOFFSET (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37) -extern TFT_T_DMA tft; +#include "t4_dsp.h" +T4_DSP tft; static int nbFiles=0; static int curFile=0; @@ -65,6 +73,8 @@ static char selected_filename[MAX_FILENAME_SIZE]=""; static char second_selected_filename[MAX_FILENAME_SIZE]=""; static bool menuRedraw=true; static bool autorun=false; +static bool vgahires=false; + static const unsigned short * keys; #ifdef TEECOMPUTER @@ -158,6 +168,29 @@ void emu_Free(void * pt) free(pt); } +#define SMEMPOOL (0x800000) +EXTMEM static unsigned char slowmem[SMEMPOOL]; +static int slowmempt = 0; + +void * emu_SMalloc(unsigned int size) +{ + void * mem = (void*)&slowmem[slowmempt]; + slowmempt += size; + + if ( slowmempt > SMEMPOOL ) { + mem = NULL; + emu_printf("failure to allocate slow"); + } + else { + emu_printf("could allocate slow static "); + emu_printf(size); + } + return mem; +} + +void emu_SFree(void * pt) +{ +} /******************************** * Input and keyboard ********************************/ @@ -329,6 +362,12 @@ int emu_ReadKeys(void) #endif if ( row & 0x02 ) retval |= MASK_JOY2_BTN; + +#ifdef EXTPAD + if ( sh_pressed ) retval |= MASK_KEY_USER3; + if ( fn_pressed ) retval |= MASK_KEY_USER1; + digitalWrite(KLED, 0); +#else // Handle LED flash uint32_t time_ms=millis(); if ((time_ms-last_t_ms) > 100) { @@ -412,8 +451,9 @@ int emu_ReadKeys(void) if ( key_fn ) retval |= MASK_KEY_USER2; if ( ( key_fn ) && (keymatrix[4] == 0x10 )) retval |= MASK_KEY_USER1; +#endif - if ( (key_fn) && (key_sh) ) + if ( (fn_pressed) && (sh_pressed) ) #else if ( ((retval & (MASK_KEY_USER1+MASK_KEY_USER2)) == (MASK_KEY_USER1+MASK_KEY_USER2)) || (retval & MASK_KEY_USER4 ) ) @@ -453,8 +493,10 @@ int emu_ReadKeys(void) while (true) { ; } -#endif +#endif } + + emu_GetJoystick(); return (retval); } @@ -607,7 +649,7 @@ int emu_setKeymap(int index) { } int emu_GetMouse(int *x, int *y, int *buts) { -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBKEY) if (mouse1.available()) { *buts = mouse1.getButtons(); *x = mouse1.getMouseX(); @@ -620,7 +662,23 @@ int emu_GetMouse(int *x, int *y, int *buts) { return 0; } -#ifdef HAS_USBKEY +int emu_GetJoystick(void) { +#if defined(HAS_USB) && (HAS_USBJOY) + for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) { + if (joysticks[joystick_index].available()) { + uint64_t axis_mask = joysticks[joystick_index].axisMask(); + uint64_t axis_changed_mask = joysticks[joystick_index].axisChangedMask(); + uint32_t buttons = joysticks[joystick_index].getButtons(); + Serial.printf("Joystick(%d): buttons = %x", joystick_index, buttons); + Serial.println(); + } + } + return 1; +#endif + return 0; +} + +#if defined(HAS_USB) && (HAS_USBKEY) void OnPress(auto key) { keyboardDetected = true; @@ -764,7 +822,7 @@ int emu_KeyboardDetected(void) { return (keyboardDetected?1:0); } -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) static unsigned char midiBuffer[16]; static unsigned char midiLastCmd=0; static int midiDataCnt=0; @@ -772,8 +830,7 @@ static int midiCmdNbParam=0; #endif void emu_MidiOnDataReceived(unsigned char value) { - -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) //Serial.println(value, HEX); //10000000 = 128 = note off //10010000 = 144 = note on @@ -941,6 +998,7 @@ void emu_MidiOnDataReceived(unsigned char value) { /******************************** * Menu file loader UI ********************************/ +#ifdef FILEBROWSER static int readNbFiles(void) { int totalFiles = 0; @@ -970,8 +1028,6 @@ static int readNbFiles(void) { return totalFiles; } - - void backgroundMenu(void) { menuRedraw=true; tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00)); @@ -981,11 +1037,13 @@ void backgroundMenu(void) { int handleMenu(uint16_t bClick) { if (autorun) { + toggleMenu(false); + menuRedraw=false; return (ACTION_RUN1); } int action = ACTION_NONE; - if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) ) { + if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) || ( bClick & MASK_KEY_USER2 ) ) { char newpath[MAX_FILENAME_PATH]; strcpy(newpath, selection); strcat(newpath, "/"); @@ -996,17 +1054,31 @@ int handleMenu(uint16_t bClick) File file = SD.open(selection); if (file.isDirectory()) { curFile = 0; - nbFiles = readNbFiles(); + nbFiles = readNbFiles(); + menuRedraw=true; } - else { - action = ACTION_RUN1; + else + { #ifdef TEECOMPUTER - if (key_extmode) { + if ( (key_extmode) || ( key_sh) ) { emu_writeConfig(); } + if ( tft.getMode() < MODE_VGA_320x240) { + if ( bClick & MASK_KEY_USER2 ) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + } + //emu_SwapJoysticks(0); #endif + toggleMenu(false); + menuRedraw=false; + return (ACTION_RUN1); } - menuRedraw=true; } else if ( bClick & MASK_KEY_USER1 ) { menuRedraw=true; @@ -1015,19 +1087,14 @@ int handleMenu(uint16_t bClick) strcat(second_selection, "/"); strcat(second_selection, second_selected_filename); action = ACTION_RUN2; - } - else if ( bClick & MASK_KEY_USER2 ) { - menuRedraw=true; - //action = ACTION_RUN3; - emu_SwapJoysticks(0); - } + } else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) { if (curFile!=0) { menuRedraw=true; curFile--; } } - else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { + else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { if ((curFile-9)>=0) { menuRedraw=true; curFile -= 9; @@ -1042,7 +1109,7 @@ int handleMenu(uint16_t bClick) menuRedraw=true; } } - else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { + else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { if ((curFile<(nbFiles-9)) && (nbFiles)) { curFile += 9; menuRedraw=true; @@ -1099,12 +1166,12 @@ int handleMenu(uint16_t bClick) return (action); } -bool menuActive(void) +int menuActive(void) { - return (menuOn); + return (menuOn?1:0); } -void toggleMenu(bool on) { +void toggleMenu(int on) { if (on) { menuOn=true; backgroundMenu(); @@ -1122,7 +1189,7 @@ char * menuSecondSelection(void) { return (second_selection); } - +#endif /******************************** * OSKB handling @@ -1140,8 +1207,9 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) char c[4] = {' ',0,' ',0}; const char * cpt = str; int i=0; - int fb_width,fb_height; - tft.get_frame_buffer_size(&fb_width, &fb_height); + int fb_width,fb_height,fbstride; + + fbstride = tft.get_frame_buffer_size(&fb_width, &fb_height); int ypos = (bottom?(fb_height-2*8):0); int line = row + (bottom?2:0); while ((c[1] = *cpt++)) @@ -1150,7 +1218,7 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0); else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff); if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff); - tft.drawTextNoDma(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); + tft.drawText(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); i++; } } @@ -1248,7 +1316,7 @@ int handleOSKB(void) { return retval; } -void toggleOSKB(bool forceon) { +void toggleOSKB(int forceon) { if (forceon) { oskbOn = true; drawOSKB(); @@ -1332,6 +1400,17 @@ int emu_FileRead(void * buf, int size, int handler) #endif } +int emu_FileWrite(void * buf, int size, int handler) +{ +// emu_printf("emu_FileWrite"); +// emu_printi(handler); +#ifdef HCFH + return (file.write(buf, size)); +#else + return (getFileHandler(handler).write(buf, size)); +#endif +} + int emu_FileGetc(int handler) { // emu_printf("FileGetc"); // emu_printi(handler); @@ -1404,6 +1483,9 @@ unsigned int emu_FileSize(const char * filepath) emu_printf(filesize); lofile.close(); } + else { + emu_printf("filesize failed"); + } return(filesize); } @@ -1489,6 +1571,48 @@ static bool emu_eraseConfig(void) SD.remove (ROMSDIR "/" AUTORUN_FILENAME); } +static bool emu_writeGfxConfig(char * display_type) +{ + bool retval = false; + SD.remove ("/" GFX_CFG_FILENAME); + if (strcmp(display_type, "VGA")) { + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(display_type, strlen(display_type)) != strlen(display_type)) { + emu_printf("GFX config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + } + return retval; +} + +#define CFG_VGA 0 +#define CFG_ILI 1 +#define CFG_ST 2 + +static int emu_readGfxConfig(void) +{ + int retval = CFG_VGA; // No file = VGA + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + if (filesize == 2) // "ST" + { + retval = CFG_ST; + } + else if (filesize == 3) // "ILI" + { + retval = CFG_ILI; + } + lofile.close(); + } + return retval; +} + /******************************** * File IO compatibility ********************************/ @@ -1670,62 +1794,249 @@ FRESULT f_mkdir (const char* path) /******************************** - * Initialization + * GFX wrapper ********************************/ -void emu_init(void) +static unsigned short palette16[PALETTE_SIZE]; +static IntervalTimer myTimer; +volatile boolean vbl=true; +volatile boolean vgatimervsync=false; +static void (*vblCallback)(void) = nullptr; +static int skip=0; + +static void vblCount() { + if (vbl) { + vbl = false; + } else { + vbl = true; + } +} + +void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) +{ + if (index= MODE_VGA_320x240 ) { + if (vgatimervsync) { + while (vbl==vb) {}; + } + else { + tft.waitSync(); + } + } + else { + while (vbl==vb) {}; + } + if (vblCallback != nullptr) { + vblCallback(); + } +} + +void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride) +{ + if (skip == 0) { + tft.writeScreenPal(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); + } +} +void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLinePal(width,height,line, VBuf, palette16); + } +} + +void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine(width,height,line, VBuf); + } +} + +void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine8(width,height,line, VBuf, palette16); + } +} + +int emu_IsVga(void) +{ + return (tft.getMode() >= MODE_VGA_320x240?1:0); +} + +int emu_IsVgaHires(void) +{ + return (tft.getMode() >= MODE_VGA_640x240?1:0); +} + +int emu_FrameSkip(void) +{ + return skip; +} + + +/******************************** + * AUDIO wrapper +********************************/ +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +AudioPlaySystem mymixer; + +void emu_sndInit() { + Serial.println("sound init"); + mymixer.begin_audio(256, mymixer.snd_Mixer); + mymixer.start(); +} + +void emu_sndPlaySound(int chan, int volume, int freq) +{ + if (chan < 6) { + mymixer.sound(chan, freq, volume); + } + /* + Serial.print(chan); + Serial.print(":" ); + Serial.print(volume); + Serial.print(":" ); + Serial.println(freq); + */ +} + +void emu_sndPlayBuzz(int size, int val) { + mymixer.buzz(size,val); + //Serial.print((val==1)?1:0); + //Serial.print(":"); + //Serial.println(size); +} +#endif + +/******************************** + * Initialization +********************************/ +void emu_init(int hires) { Serial.begin(115200); + vgahires = hires; -#ifdef HAS_USBKEY +#ifdef HAS_USB myusb.begin(); +#ifdef HAS_USBKEY keyboard1.attachPress(OnPress); keyboard1.attachRelease(OnRelease); #endif +#endif - while (!SD.begin(SD_CS)) +#ifdef FILEBROWSER + if (!SD.begin(SD_CS)) { - Serial.println("SD begin failed, retrying..."); - delay(1000); + Serial.println("No SD card detected"); } strcpy(selection,ROMSDIR); - FileHandlersInit(); - nbFiles = readNbFiles(); - - Serial.print("SD initialized, files found: "); Serial.println(nbFiles); +#endif emu_InitJoysticks(); #ifdef SWAP_JOYSTICK - joySwapped = true; + joySwapped = true; #else - joySwapped = false; + joySwapped = false; #endif -#ifdef TEECOMPUTER -#ifndef HAS_T4_VGA - tft.flipscreen(false); -#endif -#endif int keypressed = emu_ReadKeys(); +#ifdef HAS_T4_VGA + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } +#else + int gfx_mode = CFG_VGA; // default +#ifdef FILEBROWSER + gfx_mode = emu_readGfxConfig(); +#endif + // Force VGA if UP pressed + if (keypressed & MASK_JOY2_UP) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("VGA"); +#endif + gfx_mode = CFG_VGA; + } + else { + if (keypressed & MASK_JOY2_LEFT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ST"); +#endif + gfx_mode = CFG_ST; + } + else if (keypressed & MASK_JOY2_RIGHT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ILI"); +#endif + gfx_mode = CFG_ILI; + } + } + if (gfx_mode == CFG_VGA) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + else + { + tft.begin(gfx_mode == CFG_ILI?MODE_TFTILI_320x240:MODE_TFTST_320x240); + } +#endif + if (keypressed & MASK_JOY2_DOWN) { tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) ); tft.drawTextNoDma(64,48, (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); +#ifdef FILEBROWSER emu_eraseConfig(); delay(1000); +#endif } else { +#ifdef FILEBROWSER if (emu_readConfig()) { autorun = true; } +#endif } +#ifdef FILEBROWSER toggleMenu(true); +#endif } -void emu_start(void) +void emu_start(int vblms, void * callback, int forcetimervsync) { + vgatimervsync = forcetimervsync?true:false; + tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); + tft.startRefresh(); + if (callback != nullptr) { + vblCallback = callback; + } + + myTimer.begin(vblCount, vblms); +#ifdef HAS_SND + emu_sndInit(); +#endif usbnavpad = 0; } diff --git a/MCUME_teensy41/teensygen/emuapi.h b/MCUME_teensy41/teensygen/emuapi.h index 5a0bb45..5dd6130 100644 --- a/MCUME_teensy41/teensygen/emuapi.h +++ b/MCUME_teensy41/teensygen/emuapi.h @@ -2,127 +2,14 @@ #define EMUAPI_H #include "platform_config.h" - -#define CUSTOM_SND 1 -//#define TIMER_REND 1 - -#define EXTRA_HEAP 0x10000 - - -// Title: < > -#define TITLE " Genesis Emulator " -#define ROMSDIR "/gen" - -#define emu_Init(ROM) {gen_Init(); gen_Start(ROM);} -#define emu_Step(x) {gen_Step();} -#define emu_Input(x) {gen_Input(x);} - -#define MAX_FILENAME_PATH 64 -#define NB_FILE_HANDLER 4 -#define PALETTE_SIZE 1 -#define VID_FRAME_SKIP 0x0 -#define TFT_VBUFFER_YCROP 0 -#define SINGLELINE_RENDERING 1 - -#define R32(rgb) ((rgb>>16)&0xff) -#define G32(rgb) ((rgb>>8)&0xff) -#define B32(rgb) (rgb & 0xff) +#include "emucfg.h" #define ACTION_NONE 0 -#define ACTION_MAXKBDVAL 16 -#define ACTION_EXITKBD 128 -#define ACTION_RUN1 129 -#define ACTION_RUN2 130 -#define ACTION_RUN3 131 - -#ifdef KEYMAP_PRESENT - -#define keylables_map0_0 (char *)"qwertyuiop\x1a" -#define keylables_map0_1 (char *)" asdfghjkl\x19" -#define keylables_map0_2 (char *)" zxcvbnm,.;/" -#define keylables_map0_3 (char *)" +\x10-" -const unsigned short key_map0[] = { - 'q','w','e','r','t','y','u','i','o','p',157, //lowecase - 0,'a','s','d','f','g','h','j','k','l',0x0D, - 0,'z','x','c','v','b','n','m',',','.',';','/', - 145,157,29,17, - 0,'+',' ','-' - }; - -#define keylables_map1_0 (char *)"QWERTYUIOP@" -#define keylables_map1_1 (char *)" ASDFGHJKL\x19" -#define keylables_map1_2 (char *)" ZXCVBNM<>:?" -#define keylables_map1_3 (char *)" =\x10_" -const unsigned short key_map1[] = { - 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase - 0,'A','S','D','F','G','H','J','K','L',0x0D, - 0,'Z','X','C','V','B','N','M','<','>',':','?', - 145,157,29,17, - 0,'=',' ','_' - }; - -#define keylables_map2_0 (char *)"!\"#$%^&*()@" -#define keylables_map2_1 (char *)" |\\[]{} " -#define keylables_map2_2 (char *)" <>:?" -#define keylables_map2_3 (char *)" =\x10_" -const unsigned short key_map2[] = { - '!','"','#','$','%','^','&','*','(',')','@', // shiftothers - 0, '|','\\','[',']','{','}','\'',0,0,0, - 0, 0,0,0,0,0,0,0,'<','>',':','?', - 0,0,0,0, - 0,'=',' ','_' - }; - -#define keylables_map3_0 (char *)"1234567890 " -#define keylables_map3_1 (char *)" " -#define keylables_map3_2 (char *)" " -#define keylables_map3_3 (char *)" " - -const unsigned short key_map3[] = { - '1','2','3','4','5','6','7','8','9','0',0, // digit keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map4_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " -#define keylables_map4_1 (char *)" " -#define keylables_map4_2 (char *)" " -#define keylables_map4_3 (char *)" " - -const unsigned short key_map4[] = { - 133,134,135,136,137,138,139,140,0,0,0, // function keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map5_0 (char *)" " -#define keylables_map5_1 (char *)" " -#define keylables_map5_2 (char *)" " -#define keylables_map5_3 (char *)" " - -const unsigned short key_map5[] = { - 0,0,0,0,0,0,0,0,0,0,0, // extra keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -const unsigned short matkeys[] = { - 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 - 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 - 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 - 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN - 0x510,0x010,0x110,0x310, // row 4 - }; - -#endif - +#define ACTION_RUN1 1 +#define ACTION_RUN2 2 +#define FORCE_VGATIMERVSYNC 1 +#define SUPPORT_HIRES 1 #define MASK_JOY2_RIGHT 0x0001 #define MASK_JOY2_LEFT 0x0002 @@ -139,22 +26,25 @@ const unsigned short matkeys[] = { #define MASK_JOY1_BTN 0x1000 #define MASK_KEY_USER4 0x2000 +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) #ifdef __cplusplus extern "C" { +extern void emu_init(int hires=0); +extern void emu_start(int vblms, void * callback, int forcetimervsync=0); #endif - -extern void emu_init(void); -extern void emu_start(void); extern void emu_printf(const char * text); extern void emu_printi(int val); extern void emu_printh(int val); extern void * emu_Malloc(unsigned int size); extern void * emu_MallocI(unsigned int size); extern void emu_Free(void * pt); +extern void * emu_SMalloc(unsigned int size); +extern void emu_SFree(void * pt); extern int emu_FileOpen(const char * filepath, const char * mode); extern int emu_FileRead(void * buf, int size, int handler); +extern int emu_FileWrite(void * buf, int size, int handler); extern int emu_FileGetc(int handler); extern int emu_FileSeek(int handler, int seek, int origin); extern int emu_FileTell(int handler); @@ -165,24 +55,23 @@ extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size); extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek); extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index); -extern void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride); -extern void emu_DrawLine(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line); extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line); +extern void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride); extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line); -extern void emu_CopyLine(int width, int height, int ysrc, int ydst); extern void emu_DrawVsync(void); extern int emu_FrameSkip(void); -extern void * emu_LineBuffer(int line); -extern void emu_tweakVideo(int shiftdelta, int numdelta, int denomdelta); +extern int emu_IsVga(void); +extern int emu_IsVgaHires(void); -extern bool menuActive(void); +extern int menuActive(void); extern char * menuSelection(void); extern char * menuSecondSelection(void); -extern void toggleMenu(bool on); +extern void toggleMenu(int on); extern int handleMenu(unsigned short bClick); extern int handleOSKB(void); -extern void toggleOSKB(bool forceon); +extern void toggleOSKB(int forceon); extern void emu_InitJoysticks(void); extern int emu_SwapJoysticks(int statusOnly); @@ -191,6 +80,7 @@ extern int emu_ReadKeys(void); extern int emu_GetPad(void); extern int emu_GetMouse(int *x, int *y, int *buts); extern int emu_MouseDetected(void); +extern int emu_GetJoystick(void); extern int emu_KeyboardDetected(void); extern int emu_ReadAnalogJoyX(int min, int max); extern int emu_ReadAnalogJoyY(int min, int max); diff --git a/MCUME_teensy41/teensygen/emucfg.h b/MCUME_teensy41/teensygen/emucfg.h new file mode 100644 index 0000000..232e5c6 --- /dev/null +++ b/MCUME_teensy41/teensygen/emucfg.h @@ -0,0 +1,115 @@ +#ifndef EMUCFG_H +#define EMUCFG_H + +#include "wrapemu.h" + +// Title: < > +#define TITLE " Genesis Emulator " +#define ROMSDIR "/gen" + +#define emu_Init(ROM) {gen_Init(); gen_Start(ROM);} +#define emu_Step(x) {gen_Step();} +#define emu_Input(x) {gen_Input(x);} + +#define MAX_FILENAME_PATH 64 +#define NB_FILE_HANDLER 4 + +#define PALETTE_SIZE 1 +#define VID_FRAME_SKIP 0x0 +#define TFT_VBUFFER_YCROP 0 +#define SINGLELINE_RENDERING 1 +#define CUSTOM_SND 1 +//#define TIMER_REND 1 +//#define EXTPAD 1 +#define EXTRA_HEAP 0x10000 +#define FILEBROWSER 1 + + +#ifdef KEYMAP_PRESENT + +#define keylables_map0_0 (char *)"qwertyuiop\x1a" +#define keylables_map0_1 (char *)" asdfghjkl\x19" +#define keylables_map0_2 (char *)" zxcvbnm,.;/" +#define keylables_map0_3 (char *)" +\x10-" +const unsigned short key_map0[] = { + 'q','w','e','r','t','y','u','i','o','p',157, //lowecase + 0,'a','s','d','f','g','h','j','k','l',0x0D, + 0,'z','x','c','v','b','n','m',',','.',';','/', + 145,157,29,17, + 0,'+',' ','-' + }; + +#define keylables_map1_0 (char *)"QWERTYUIOP@" +#define keylables_map1_1 (char *)" ASDFGHJKL\x19" +#define keylables_map1_2 (char *)" ZXCVBNM<>:?" +#define keylables_map1_3 (char *)" =\x10_" +const unsigned short key_map1[] = { + 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase + 0,'A','S','D','F','G','H','J','K','L',0x0D, + 0,'Z','X','C','V','B','N','M','<','>',':','?', + 145,157,29,17, + 0,'=',' ','_' + }; + +#define keylables_map2_0 (char *)"!\"#$%^&*()@" +#define keylables_map2_1 (char *)" |\\[]{} " +#define keylables_map2_2 (char *)" <>:?" +#define keylables_map2_3 (char *)" =\x10_" +const unsigned short key_map2[] = { + '!','"','#','$','%','^','&','*','(',')','@', // shiftothers + 0, '|','\\','[',']','{','}','\'',0,0,0, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 0,0,0,0, + 0,'=',' ','_' + }; + +#define keylables_map3_0 (char *)"1234567890 " +#define keylables_map3_1 (char *)" " +#define keylables_map3_2 (char *)" " +#define keylables_map3_3 (char *)" " + +const unsigned short key_map3[] = { + '1','2','3','4','5','6','7','8','9','0',0, // digit keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map4_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " +#define keylables_map4_1 (char *)" " +#define keylables_map4_2 (char *)" " +#define keylables_map4_3 (char *)" " + +const unsigned short key_map4[] = { + 133,134,135,136,137,138,139,140,0,0,0, // function keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map5_0 (char *)" " +#define keylables_map5_1 (char *)" " +#define keylables_map5_2 (char *)" " +#define keylables_map5_3 (char *)" " + +const unsigned short key_map5[] = { + 0,0,0,0,0,0,0,0,0,0,0, // extra keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +const unsigned short matkeys[] = { + 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 + 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 + 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 + 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN + 0x510,0x010,0x110,0x310, // row 4 + }; + +#endif + +#endif diff --git a/MCUME_teensy41/teensygen/fm.c b/MCUME_teensy41/teensygen/fm.c index 279b079..e46a86e 100644 --- a/MCUME_teensy41/teensygen/fm.c +++ b/MCUME_teensy41/teensygen/fm.c @@ -1,1495 +1,1495 @@ - -#include "shared.h" -#include - -#ifndef PI -#define PI 3.14159265358979323846 -#endif - -#define BUILD_OPN (BUILD_YM2612) -#define BUILD_STEREO (BUILD_YM2612) -#define BUILD_LFO (BUILD_YM2612) - -#define SIN_ENT 2048 -#define ENV_BITS 16 -#define EG_ENT 4096 -#define EG_STEP (96.0/EG_ENT) /* OPL == 0.1875 dB */ - -#if FM_LFO_SUPPORT -/* LFO table entries */ -#define LFO_ENT 512 -#define LFO_SHIFT (32-9) -#define LFO_RATE 0x10000 -#endif - -/* -------------------- preliminary define section --------------------- */ -/* attack/decay rate time rate */ -#define OPM_ARRATE 399128 -#define OPM_DRRATE 5514396 -/* It is not checked , because I haven't YM2203 rate */ -#define OPN_ARRATE OPM_ARRATE -#define OPN_DRRATE OPM_DRRATE - -/* PG output cut off level : 78dB(14bit)? */ -#define PG_CUT_OFF ((int)(78.0/EG_STEP)) -/* EG output cut off level : 68dB? */ -#define EG_CUT_OFF ((int)(68.0/EG_STEP)) - -#define FREQ_BITS 24 /* frequency turn */ - -/* PG counter is 21bits @oct.7 */ -#define FREQ_RATE (1<<(FREQ_BITS-21)) -#define TL_BITS (FREQ_BITS+2) -/* OPbit = 14(13+sign) : TL_BITS+1(sign) / output = 16bit */ -#define TL_SHIFT (TL_BITS+1-(14-16)) - -/* output final shift */ -#define FM_OUTSB (TL_SHIFT-FM_OUTPUT_BIT) -#define FM_MAXOUT ((1<<(TL_SHIFT-1))-1) -#define FM_MINOUT (-(1<<(TL_SHIFT-1))) - -/* -------------------- local defines , macros --------------------- */ - -/* envelope counter position */ -#define EG_AST 0 /* start of Attack phase */ -#define EG_AED (EG_ENT<>2)&3) -#define OPM_CHAN(N) (N&7) -#define OPM_SLOT(N) ((N>>3)&3) -/* slot number */ -#define SLOT1 0 -#define SLOT2 2 -#define SLOT3 1 -#define SLOT4 3 - -/* bit0 = Right enable , bit1 = Left enable */ -#define OUTD_RIGHT 1 -#define OUTD_LEFT 2 -#define OUTD_CENTER 3 - -/* FM timer model */ -#define FM_TIMER_SINGLE (0) -#define FM_TIMER_INTERVAL (1) - -/* ---------- OPN / OPM one channel ---------- */ -typedef struct fm_slot { - INT32 *DT; /* detune :DT_TABLE[DT] */ - int DT2; /* multiple,Detune2:(DT2<<4)|ML for OPM*/ - int TL; /* total level :TL << 8 */ - UINT8 KSR; /* key scale rate :3-KSR */ - const INT32 *AR; /* attack rate :&AR_TABLE[AR<<1] */ - const INT32 *DR; /* decay rate :&DR_TABLE[DR<<1] */ - const INT32 *SR; /* sustin rate :&DR_TABLE[SR<<1] */ - int SL; /* sustin level :SL_TABLE[SL] */ - const INT32 *RR; /* release rate :&DR_TABLE[RR<<2+2] */ - UINT8 SEG; /* SSG EG type :SSGEG */ - UINT8 ksr; /* key scale rate :kcode>>(3-KSR) */ - UINT32 mul; /* multiple :ML_TABLE[ML] */ - /* Phase Generator */ - UINT32 Cnt; /* frequency count : */ - UINT32 Incr; /* frequency step : */ - /* Envelope Generator */ - void (*eg_next)(struct fm_slot *SLOT); /* pointer of phase handler */ - INT32 evc; /* envelope counter */ - INT32 eve; /* envelope counter end point */ - INT32 evs; /* envelope counter step */ - INT32 evsa; /* envelope step for Attack */ - INT32 evsd; /* envelope step for Decay */ - INT32 evss; /* envelope step for Sustain */ - INT32 evsr; /* envelope step for Release */ - INT32 TLL; /* adjusted TotalLevel */ - /* LFO */ - UINT8 amon; /* AMS enable flag */ - UINT32 ams; /* AMS depth level of this SLOT */ -}FM_SLOT; - -typedef struct fm_chan { - FM_SLOT SLOT[4]; - UINT8 PAN; /* PAN :NONE,LEFT,RIGHT or CENTER */ - UINT8 ALGO; /* Algorythm */ - UINT8 FB; /* shift count of self feed back */ - INT32 op1_out[2]; /* op1 output for beedback */ - /* Algorythm (connection) */ - INT32 *connect1; /* pointer of SLOT1 output */ - INT32 *connect2; /* pointer of SLOT2 output */ - INT32 *connect3; /* pointer of SLOT3 output */ - INT32 *connect4; /* pointer of SLOT4 output */ - /* LFO */ - INT32 pms; /* PMS depth level of channel */ - UINT32 ams; /* AMS depth level of channel */ - /* Phase Generator */ - UINT32 fc; /* fnum,blk :adjusted to sampling rate */ - UINT8 fn_h; /* freq latch : */ - UINT8 kcode; /* key code : */ -} FM_CH; - -/* OPN/OPM common state */ -typedef struct fm_state { - UINT8 index; /* chip index (number of chip) */ - int clock; /* master clock (Hz) */ - int rate; /* sampling rate (Hz) */ - double freqbase; /* frequency base */ - double TimerBase; /* Timer base time */ - UINT8 address; /* address register */ - UINT8 irq; /* interrupt level */ - UINT8 irqmask; /* irq mask */ - UINT8 status; /* status flag */ - UINT32 mode; /* mode CSM / 3SLOT */ - int TA; /* timer a */ - int TAC; /* timer a counter */ - UINT8 TB; /* timer b */ - int TBC; /* timer b counter */ - /* speedup customize */ - /* local time tables */ - INT32 DT_TABLE[8][32]; /* DeTune tables */ - INT32 AR_TABLE[94]; /* Atttack rate tables */ - INT32 DR_TABLE[94]; /* Decay rate tables */ - /* Extention Timer and IRQ handler */ - FM_TIMERHANDLER Timer_Handler; - FM_IRQHANDLER IRQ_Handler; - /* timer model single / interval */ - UINT8 timermodel; -}FM_ST; - -/* -------------------- tables --------------------- */ - -/* sustain lebel table (3db per step) */ -/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ -#define SC(db) (int)((db*((3/EG_STEP)*(1< max ) val = max; \ - else if ( val < min ) val = min; \ -} - -/* ----- buffering one of data(STEREO chip) ----- */ -#if FM_STEREO_MIX -/* stereo mixing */ -#define FM_BUFFERING_STEREO \ -{ \ - /* get left & right output with clipping */ \ - out_ch[OUTD_LEFT] += out_ch[OUTD_CENTER]; \ - Limit( out_ch[OUTD_LEFT] , FM_MAXOUT, FM_MINOUT ); \ - out_ch[OUTD_RIGHT] += out_ch[OUTD_CENTER]; \ - Limit( out_ch[OUTD_RIGHT], FM_MAXOUT, FM_MINOUT ); \ - /* buffering */ \ - *bufL++ = out_ch[OUTD_LEFT] >>FM_OUTSB; \ - *bufL++ = out_ch[OUTD_RIGHT]>>FM_OUTSB; \ -} -#else -/* stereo separate */ -#define FM_BUFFERING_STEREO \ -{ \ - /* get left & right output with clipping */ \ - out_ch[OUTD_LEFT] += out_ch[OUTD_CENTER]; \ - Limit( out_ch[OUTD_LEFT] , FM_MAXOUT, FM_MINOUT ); \ - out_ch[OUTD_RIGHT] += out_ch[OUTD_CENTER]; \ - Limit( out_ch[OUTD_RIGHT], FM_MAXOUT, FM_MINOUT ); \ - /* buffering */ \ - bufL[i] = out_ch[OUTD_LEFT] >>FM_OUTSB; \ - bufR[i] = out_ch[OUTD_RIGHT]>>FM_OUTSB; \ -} -#endif - -#if FM_INTERNAL_TIMER -/* ----- internal timer mode , update timer */ -/* ---------- calcrate timer A ---------- */ -#define INTERNAL_TIMER_A(ST,CSM_CH) \ -{ \ - if( ST->TAC && (ST->Timer_Handler==0) ) \ - if( (ST->TAC -= (int)(ST->freqbase*4096)) <= 0 ) \ - { \ - TimerAOver( ST ); \ - /* CSM mode total level latch and auto key on */ \ - if( ST->mode & 0x80 ) \ - CSMKeyControll( CSM_CH ); \ - } \ -} -/* ---------- calcrate timer B ---------- */ -#define INTERNAL_TIMER_B(ST,step) \ -{ \ - if( ST->TBC && (ST->Timer_Handler==0) ) \ - if( (ST->TBC -= (int)(ST->freqbase*4096*step)) <= 0 ) \ - TimerBOver( ST ); \ -} -#else /* FM_INTERNAL_TIMER */ -/* external timer mode */ -#define INTERNAL_TIMER_A(ST,CSM_CH) -#define INTERNAL_TIMER_B(ST,step) -#endif /* FM_INTERNAL_TIMER */ - -/* --------------------- subroutines --------------------- */ -/* status set and IRQ handling */ -static __inline__ void FM_STATUS_SET(FM_ST *ST,int flag) -{ - /* set status flag */ - ST->status |= flag; - if ( !(ST->irq) && (ST->status & ST->irqmask) ) - { - ST->irq = 1; - /* callback user interrupt handler (IRQ is OFF to ON) */ - if(ST->IRQ_Handler) (ST->IRQ_Handler)(ST->index,1); - } -} - -/* status reset and IRQ handling */ -static __inline__ void FM_STATUS_RESET(FM_ST *ST,int flag) -{ - /* reset status flag */ - ST->status &=~flag; - if ( (ST->irq) && !(ST->status & ST->irqmask) ) - { - ST->irq = 0; - /* callback user interrupt handler (IRQ is ON to OFF) */ - if(ST->IRQ_Handler) (ST->IRQ_Handler)(ST->index,0); - } -} - -/* IRQ mask set */ -static __inline__ void FM_IRQMASK_SET(FM_ST *ST,int flag) -{ - ST->irqmask = flag; - /* IRQ handling check */ - FM_STATUS_SET(ST,0); - FM_STATUS_RESET(ST,0); -} - -/* ---------- event hander of Phase Generator ---------- */ - -/* Release end -> stop counter */ -static void FM_EG_Release( FM_SLOT *SLOT ) -{ - SLOT->evc = EG_OFF; - SLOT->eve = EG_OFF+1; - SLOT->evs = 0; -} - -/* SUSTAIN end -> stop counter */ -static void FM_EG_SR( FM_SLOT *SLOT ) -{ - SLOT->evs = 0; - SLOT->evc = EG_OFF; - SLOT->eve = EG_OFF+1; -} - -/* Decay end -> Sustain */ -static void FM_EG_DR( FM_SLOT *SLOT ) -{ - SLOT->eg_next = FM_EG_SR; - SLOT->evc = SLOT->SL; - SLOT->eve = EG_DED; - SLOT->evs = SLOT->evss; -} - -/* Attack end -> Decay */ -static void FM_EG_AR( FM_SLOT *SLOT ) -{ - /* next DR */ - SLOT->eg_next = FM_EG_DR; - SLOT->evc = EG_DST; - SLOT->eve = SLOT->SL; - SLOT->evs = SLOT->evsd; -} - -#if FM_SEG_SUPPORT -static void FM_EG_SSG_SR( FM_SLOT *SLOT ); - -/* SEG down side end */ -static void FM_EG_SSG_DR( FM_SLOT *SLOT ) -{ - if( SLOT->SEG&2){ - /* reverce */ - SLOT->eg_next = FM_EG_SSG_SR; - SLOT->evc = SLOT->SL + (EG_UST - EG_DST); - SLOT->eve = EG_UED; - SLOT->evs = SLOT->evss; - }else{ - /* again */ - SLOT->evc = EG_DST; - } - /* hold */ - if( SLOT->SEG&1) SLOT->evs = 0; -} - -/* SEG upside side end */ -static void FM_EG_SSG_SR( FM_SLOT *SLOT ) -{ - if( SLOT->SEG&2){ - /* reverce */ - SLOT->eg_next = FM_EG_SSG_DR; - SLOT->evc = EG_DST; - SLOT->eve = EG_DED; - SLOT->evs = SLOT->evsd; - }else{ - /* again */ - SLOT->evc = SLOT->SL + (EG_UST - EG_DST); - } - /* hold check */ - if( SLOT->SEG&1) SLOT->evs = 0; -} - -/* SEG Attack end */ -static void FM_EG_SSG_AR( FM_SLOT *SLOT ) -{ - if( SLOT->SEG&4){ /* start direction */ - /* next SSG-SR (upside start ) */ - SLOT->eg_next = FM_EG_SSG_SR; - SLOT->evc = SLOT->SL + (EG_UST - EG_DST); - SLOT->eve = EG_UED; - SLOT->evs = SLOT->evss; - }else{ - /* next SSG-DR (downside start ) */ - SLOT->eg_next = FM_EG_SSG_DR; - SLOT->evc = EG_DST; - SLOT->eve = EG_DED; - SLOT->evs = SLOT->evsd; - } -} -#endif /* FM_SEG_SUPPORT */ - -/* ----- key on of SLOT ----- */ -#define FM_KEY_IS(SLOT) ((SLOT)->eg_next!=FM_EG_Release) - -static __inline__ void FM_KEYON(FM_CH *CH , int s ) -{ - FM_SLOT *SLOT = &CH->SLOT[s]; - if( !FM_KEY_IS(SLOT) ) - { - /* restart Phage Generator */ - SLOT->Cnt = 0; - /* phase -> Attack */ -#if FM_SEG_SUPPORT - if( SLOT->SEG&8 ) SLOT->eg_next = FM_EG_SSG_AR; - else -#endif - SLOT->eg_next = FM_EG_AR; - SLOT->evs = SLOT->evsa; -#if 0 - /* convert decay count to attack count */ - /* --- This caused the problem by credit sound of paper boy. --- */ - SLOT->evc = EG_AST + DRAR_TABLE[ENV_CURVE[SLOT->evc>>ENV_BITS]];/* + SLOT->evs;*/ -#else - /* reset attack counter */ - SLOT->evc = EG_AST; -#endif - SLOT->eve = EG_AED; - } -} -/* ----- key off of SLOT ----- */ -static __inline__ void FM_KEYOFF(FM_CH *CH , int s ) -{ - FM_SLOT *SLOT = &CH->SLOT[s]; - if( FM_KEY_IS(SLOT) ) - { - /* if Attack phase then adjust envelope counter */ - if( SLOT->evc < EG_DST ) - SLOT->evc = (ENV_CURVE[SLOT->evc>>ENV_BITS]< Release */ - SLOT->eg_next = FM_EG_Release; - SLOT->eve = EG_DED; - SLOT->evs = SLOT->evsr; - } -} - -/* setup Algorythm and PAN connection */ -static void setup_connection( FM_CH *CH ) -{ - INT32 *carrier = &out_ch[CH->PAN]; /* NONE,LEFT,RIGHT or CENTER */ - - switch( CH->ALGO ){ - case 0: - /* PG---S1---S2---S3---S4---OUT */ - CH->connect1 = &pg_in2; - CH->connect2 = &pg_in3; - CH->connect3 = &pg_in4; - break; - case 1: - /* PG---S1-+-S3---S4---OUT */ - /* PG---S2-+ */ - CH->connect1 = &pg_in3; - CH->connect2 = &pg_in3; - CH->connect3 = &pg_in4; - break; - case 2: - /* PG---S1------+-S4---OUT */ - /* PG---S2---S3-+ */ - CH->connect1 = &pg_in4; - CH->connect2 = &pg_in3; - CH->connect3 = &pg_in4; - break; - case 3: - /* PG---S1---S2-+-S4---OUT */ - /* PG---S3------+ */ - CH->connect1 = &pg_in2; - CH->connect2 = &pg_in4; - CH->connect3 = &pg_in4; - break; - case 4: - /* PG---S1---S2-+--OUT */ - /* PG---S3---S4-+ */ - CH->connect1 = &pg_in2; - CH->connect2 = carrier; - CH->connect3 = &pg_in4; - break; - case 5: - /* +-S2-+ */ - /* PG---S1-+-S3-+-OUT */ - /* +-S4-+ */ - CH->connect1 = 0; /* special case */ - CH->connect2 = carrier; - CH->connect3 = carrier; - break; - case 6: - /* PG---S1---S2-+ */ - /* PG--------S3-+-OUT */ - /* PG--------S4-+ */ - CH->connect1 = &pg_in2; - CH->connect2 = carrier; - CH->connect3 = carrier; - break; - case 7: - /* PG---S1-+ */ - /* PG---S2-+-OUT */ - /* PG---S3-+ */ - /* PG---S4-+ */ - CH->connect1 = carrier; - CH->connect2 = carrier; - CH->connect3 = carrier; - } - CH->connect4 = carrier; -} - -/* set detune & multiple */ -static __inline__ void set_det_mul(FM_ST *ST,FM_CH *CH,FM_SLOT *SLOT,int v) -{ - SLOT->mul = MUL_TABLE[v&0x0f]; - SLOT->DT = ST->DT_TABLE[(v>>4)&7]; - CH->SLOT[SLOT1].Incr=-1; -} - -/* set total level */ -static __inline__ void set_tl(FM_CH *CH,FM_SLOT *SLOT , int v,int csmflag) -{ - v &= 0x7f; - v = (v<<7)|v; /* 7bit -> 14bit */ - SLOT->TL = (v*EG_ENT)>>14; - /* if it is not a CSM channel , latch the total level */ - if( !csmflag ) - SLOT->TLL = SLOT->TL; -} - -/* set attack rate & key scale */ -static __inline__ void set_ar_ksr(FM_CH *CH,FM_SLOT *SLOT,int v,INT32 *ar_table) -{ - SLOT->KSR = 3-(v>>6); - SLOT->AR = (v&=0x1f) ? &ar_table[v<<1] : RATE_0; - SLOT->evsa = SLOT->AR[SLOT->ksr]; - if( SLOT->eg_next == FM_EG_AR ) SLOT->evs = SLOT->evsa; - CH->SLOT[SLOT1].Incr=-1; -} -/* set decay rate */ -static __inline__ void set_dr(FM_SLOT *SLOT,int v,INT32 *dr_table) -{ - SLOT->DR = (v&=0x1f) ? &dr_table[v<<1] : RATE_0; - SLOT->evsd = SLOT->DR[SLOT->ksr]; - if( SLOT->eg_next == FM_EG_DR ) SLOT->evs = SLOT->evsd; -} -/* set sustain rate */ -static __inline__ void set_sr(FM_SLOT *SLOT,int v,INT32 *dr_table) -{ - SLOT->SR = (v&=0x1f) ? &dr_table[v<<1] : RATE_0; - SLOT->evss = SLOT->SR[SLOT->ksr]; - if( SLOT->eg_next == FM_EG_SR ) SLOT->evs = SLOT->evss; -} -/* set release rate */ -static __inline__ void set_sl_rr(FM_SLOT *SLOT,int v,INT32 *dr_table) -{ - SLOT->SL = SL_TABLE[(v>>4)]; - SLOT->RR = &dr_table[((v&0x0f)<<2)|2]; - SLOT->evsr = SLOT->RR[SLOT->ksr]; - if( SLOT->eg_next == FM_EG_Release ) SLOT->evs = SLOT->evsr; -} - -/* operator output calcrator */ -#define OP_OUT(PG,EG) SIN_TABLE[(PG/(0x1000000/SIN_ENT))&(SIN_ENT-1)][EG] -#define OP_OUTN(PG,EG) NOISE_TABLE[(PG/(0x1000000/SIN_ENT))&(SIN_ENT-1)][EG] - -/* eg calcration */ -#if FM_LFO_SUPPORT -#define FM_CALC_EG(OUT,SLOT) \ -{ \ - if( (SLOT.evc += SLOT.evs) >= SLOT.eve) \ - SLOT.eg_next(&(SLOT)); \ - OUT = SLOT.TLL+ENV_CURVE[SLOT.evc>>ENV_BITS]; \ - if(SLOT.ams) \ - OUT += (SLOT.ams*lfo_amd/LFO_RATE); \ -} -#else -#define FM_CALC_EG(OUT,SLOT) \ -{ \ - if( (SLOT.evc += SLOT.evs) >= SLOT.eve) \ - SLOT.eg_next(&(SLOT)); \ - OUT = SLOT.TLL+ENV_CURVE[SLOT.evc>>ENV_BITS]; \ -} -#endif - -/* ---------- calcrate one of channel ---------- */ -static __inline__ void FM_CALC_CH( FM_CH *CH ) -{ - UINT32 eg_out1,eg_out2,eg_out3,eg_out4; //envelope output - - /* Phase Generator */ -#if FM_LFO_SUPPORT - INT32 pms = lfo_pmd * CH->pms / LFO_RATE; - if(pms) - { - pg_in1 = (CH->SLOT[SLOT1].Cnt += CH->SLOT[SLOT1].Incr + (INT32)(pms * CH->SLOT[SLOT1].Incr) / PMS_RATE); - pg_in2 = (CH->SLOT[SLOT2].Cnt += CH->SLOT[SLOT2].Incr + (INT32)(pms * CH->SLOT[SLOT2].Incr) / PMS_RATE); - pg_in3 = (CH->SLOT[SLOT3].Cnt += CH->SLOT[SLOT3].Incr + (INT32)(pms * CH->SLOT[SLOT3].Incr) / PMS_RATE); - pg_in4 = (CH->SLOT[SLOT4].Cnt += CH->SLOT[SLOT4].Incr + (INT32)(pms * CH->SLOT[SLOT4].Incr) / PMS_RATE); - } - else -#endif - { - pg_in1 = (CH->SLOT[SLOT1].Cnt += CH->SLOT[SLOT1].Incr); - pg_in2 = (CH->SLOT[SLOT2].Cnt += CH->SLOT[SLOT2].Incr); - pg_in3 = (CH->SLOT[SLOT3].Cnt += CH->SLOT[SLOT3].Incr); - pg_in4 = (CH->SLOT[SLOT4].Cnt += CH->SLOT[SLOT4].Incr); - } - - /* Envelope Generator */ - FM_CALC_EG(eg_out1,CH->SLOT[SLOT1]); - FM_CALC_EG(eg_out2,CH->SLOT[SLOT2]); - FM_CALC_EG(eg_out3,CH->SLOT[SLOT3]); - FM_CALC_EG(eg_out4,CH->SLOT[SLOT4]); - - /* Connection */ - if( eg_out1 < EG_CUT_OFF ) /* SLOT 1 */ - { - if( CH->FB ){ - /* with self feed back */ - pg_in1 += (CH->op1_out[0]+CH->op1_out[1])>>CH->FB; - CH->op1_out[1] = CH->op1_out[0]; - } - CH->op1_out[0] = OP_OUT(pg_in1,eg_out1); - /* output slot1 */ - if( !CH->connect1 ) - { - /* algorythm 5 */ - pg_in2 += CH->op1_out[0]; - pg_in3 += CH->op1_out[0]; - pg_in4 += CH->op1_out[0]; - }else{ - /* other algorythm */ - *CH->connect1 += CH->op1_out[0]; - } - } - if( eg_out2 < EG_CUT_OFF ) /* SLOT 2 */ - *CH->connect2 += OP_OUT(pg_in2,eg_out2); - if( eg_out3 < EG_CUT_OFF ) /* SLOT 3 */ - *CH->connect3 += OP_OUT(pg_in3,eg_out3); - if( eg_out4 < EG_CUT_OFF ) /* SLOT 4 */ - *CH->connect4 += OP_OUT(pg_in4,eg_out4); -} -/* ---------- frequency counter for operater update ---------- */ -static __inline__ void CALC_FCSLOT(FM_SLOT *SLOT , int fc , int kc ) -{ - int ksr; - - /* frequency step counter */ - SLOT->Incr= (fc+SLOT->DT[kc])*SLOT->mul; /* verified on real chip */ - /* SLOT->Incr= fc*SLOT->mul + SLOT->DT[kc]; */ - ksr = kc >> SLOT->KSR; - if( SLOT->ksr != ksr ) - { - SLOT->ksr = ksr; - /* attack , decay rate recalcration */ - SLOT->evsa = SLOT->AR[ksr]; - SLOT->evsd = SLOT->DR[ksr]; - SLOT->evss = SLOT->SR[ksr]; - SLOT->evsr = SLOT->RR[ksr]; - } -} - -/* ---------- frequency counter ---------- */ -static __inline__ void OPN_CALC_FCOUNT(FM_CH *CH ) -{ - if( CH->SLOT[SLOT1].Incr==-1){ - int fc = CH->fc; - int kc = CH->kcode; - CALC_FCSLOT(&CH->SLOT[SLOT1] , fc , kc ); - CALC_FCSLOT(&CH->SLOT[SLOT2] , fc , kc ); - CALC_FCSLOT(&CH->SLOT[SLOT3] , fc , kc ); - CALC_FCSLOT(&CH->SLOT[SLOT4] , fc , kc ); - } -} - -/* ----------- initialize time tabls ----------- */ -static void init_timetables( FM_ST *ST , UINT8 *DTTABLE , int ARRATE , int DRRATE ) -{ - int i,d; - double rate; - - /* DeTune table */ - for (d = 0;d <= 3;d++){ - for (i = 0;i <= 31;i++){ - rate = (double)DTTABLE[d*32 + i] * ST->freqbase * FREQ_RATE; - ST->DT_TABLE[d][i] = (INT32) rate; - ST->DT_TABLE[d+4][i] = (INT32)-rate; - } - } - /* make Attack & Decay tables */ - for (i = 0;i < 4;i++) ST->AR_TABLE[i] = ST->DR_TABLE[i] = 0; - for (i = 4;i < 64;i++){ - rate = ST->freqbase; /* frequency rate */ - if( i < 60 ) rate *= 1.0+(i&3)*0.25; /* b0-1 : x1 , x1.25 , x1.5 , x1.75 */ - rate *= 1<<((i>>2)-1); /* b2-5 : shift bit */ - rate *= (double)(EG_ENT<AR_TABLE[i] = (INT32)(rate / ARRATE); - ST->DR_TABLE[i] = (INT32)(rate / DRRATE); - } - ST->AR_TABLE[62] = EG_AED; - ST->AR_TABLE[63] = EG_AED; - for (i = 64;i < 94 ;i++){ /* make for overflow area */ - ST->AR_TABLE[i] = ST->AR_TABLE[63]; - ST->DR_TABLE[i] = ST->DR_TABLE[63]; - } - -} - -/* ---------- reset one of channel ---------- */ -static void reset_channel( FM_ST *ST , FM_CH *CH , int chan ) -{ - int c,s; - - ST->mode = 0; /* normal mode */ - FM_STATUS_RESET(ST,0xff); - ST->TA = 0; - ST->TAC = 0; - ST->TB = 0; - ST->TBC = 0; - - for( c = 0 ; c < chan ; c++ ) - { - CH[c].fc = 0; - CH[c].PAN = OUTD_CENTER; - for(s = 0 ; s < 4 ; s++ ) - { - CH[c].SLOT[s].SEG = 0; - CH[c].SLOT[s].eg_next= FM_EG_Release; - CH[c].SLOT[s].evc = EG_OFF; - CH[c].SLOT[s].eve = EG_OFF+1; - CH[c].SLOT[s].evs = 0; - } - } -} - - -/* ---------- generic table initialize ---------- */ -static int FMInitTable( void ) -{ - int s,t; - double rate; - int i,j; - double pom; - - /* allocate total level table plus+minus section */ - TL_TABLE = (INT32 *)emu_Malloc(2*TL_MAX*sizeof(int)); - if( TL_TABLE == 0 ) return 0; - /* make total level table */ - for (t = 0;t < TL_MAX ;t++){ - if(t >= PG_CUT_OFF) - rate = 0; /* under cut off area */ - else - rate = ((1< voltage */ - TL_TABLE[ t] = (int)rate; - TL_TABLE[TL_MAX+t] = -TL_TABLE[t]; - } - - /* make sinwave table (pointer of total level) */ - for (s = 1;s <= SIN_ENT/4;s++){ - pom = sin(2.0*PI*s/SIN_ENT); /* sin */ - pom = 20*log10(1/pom); /* -> decibel */ - j = (int)(pom / EG_STEP); /* TL_TABLE steps */ - /* cut off check */ - if(j > PG_CUT_OFF) - j = PG_CUT_OFF; - /* degree 0 - 90 , degree 180 - 90 : plus section */ - SIN_TABLE[ s] = SIN_TABLE[SIN_ENT/2-s] = &TL_TABLE[j]; - /* degree 180 - 270 , degree 360 - 270 : minus section */ - SIN_TABLE[SIN_ENT/2+s] = SIN_TABLE[SIN_ENT -s] = &TL_TABLE[TL_MAX+j]; - - } - /* degree 0 = degree 180 = off */ - SIN_TABLE[0] = SIN_TABLE[SIN_ENT/2] = &TL_TABLE[PG_CUT_OFF]; - - /* envelope counter -> envelope output table */ - for (i=0; i= EG_ENT ) pom = EG_ENT-1; */ - ENV_CURVE[i] = (int)pom; - /* DECAY ,RELEASE curve */ - ENV_CURVE[(EG_DST>>ENV_BITS)+i]= i; -#if FM_SEG_SUPPORT - /* DECAY UPSIDE (SSG ENV) */ - ENV_CURVE[(EG_UST>>ENV_BITS)+i]= EG_ENT-1-i; -#endif - } - /* off */ - ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1; - - /* decay to reattack envelope converttable */ - j = EG_ENT-1; - for (i=0; imode = v; - - /* reset Timer b flag */ - if( v & 0x20 ) - FM_STATUS_RESET(ST,0x02); - /* reset Timer a flag */ - if( v & 0x10 ) - FM_STATUS_RESET(ST,0x01); - /* load b */ - if( v & 0x02 ) - { - if( ST->TBC == 0 ) - { - ST->TBC = ( 256-ST->TB)<<4; - /* External timer handler */ - if (ST->Timer_Handler) (ST->Timer_Handler)(n,1,ST->TBC,ST->TimerBase); - } - }else if (ST->timermodel == FM_TIMER_INTERVAL) - { /* stop interbval timer */ - if( ST->TBC != 0 ) - { - ST->TBC = 0; - if (ST->Timer_Handler) (ST->Timer_Handler)(n,1,0,ST->TimerBase); - } - } - /* load a */ - if( v & 0x01 ) - { - if( ST->TAC == 0 ) - { - ST->TAC = (1024-ST->TA); - /* External timer handler */ - if (ST->Timer_Handler) (ST->Timer_Handler)(n,0,ST->TAC,ST->TimerBase); - } - }else if (ST->timermodel == FM_TIMER_INTERVAL) - { /* stop interbval timer */ - if( ST->TAC != 0 ) - { - ST->TAC = 0; - if (ST->Timer_Handler) (ST->Timer_Handler)(n,0,0,ST->TimerBase); - } - } -} - -/* Timer A Overflow */ -static __inline__ void TimerAOver(FM_ST *ST) -{ - /* status set if enabled */ - if(ST->mode & 0x04) FM_STATUS_SET(ST,0x01); - /* clear or reload the counter */ - if (ST->timermodel == FM_TIMER_INTERVAL) - { - ST->TAC = (1024-ST->TA); - if (ST->Timer_Handler) (ST->Timer_Handler)(ST->index,0,ST->TAC,ST->TimerBase); - } - else ST->TAC = 0; -} -/* Timer B Overflow */ -static __inline__ void TimerBOver(FM_ST *ST) -{ - /* status set if enabled */ - if(ST->mode & 0x08) FM_STATUS_SET(ST,0x02); - /* clear or reload the counter */ - if (ST->timermodel == FM_TIMER_INTERVAL) - { - ST->TBC = ( 256-ST->TB)<<4; - if (ST->Timer_Handler) (ST->Timer_Handler)(ST->index,1,ST->TBC,ST->TimerBase); - } - else ST->TBC = 0; -} -/* CSM Key Controll */ -static __inline__ void CSMKeyControll(FM_CH *CH) -{ - /* all key off */ - /* FM_KEYOFF(CH,SLOT1); */ - /* FM_KEYOFF(CH,SLOT2); */ - /* FM_KEYOFF(CH,SLOT3); */ - /* FM_KEYOFF(CH,SLOT4); */ - /* total level latch */ - CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL; - CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL; - CH->SLOT[SLOT3].TLL = CH->SLOT[SLOT3].TL; - CH->SLOT[SLOT4].TLL = CH->SLOT[SLOT4].TL; - /* all key on */ - FM_KEYON(CH,SLOT1); - FM_KEYON(CH,SLOT2); - FM_KEYON(CH,SLOT3); - FM_KEYON(CH,SLOT4); -} - -#if BUILD_OPN -/***********************************************************/ -/* OPN unit */ -/***********************************************************/ - -/* OPN 3slot struct */ -typedef struct opn_3slot { - UINT32 fc[3]; /* fnum3,blk3 :calcrated */ - UINT8 fn_h[3]; /* freq3 latch */ - UINT8 kcode[3]; /* key code : */ -}FM_3SLOT; - -/* OPN/A/B common state */ -typedef struct opn_f { - UINT8 type; /* chip type */ - FM_ST ST; /* general state */ - FM_3SLOT SL3; /* 3 slot mode state */ - FM_CH *P_CH; /* pointer of CH */ - UINT32 FN_TABLE[2048]; /* fnumber -> increment counter */ -#if FM_LFO_SUPPORT - /* LFO */ - UINT32 LFOCnt; - UINT32 LFOIncr; - UINT32 LFO_FREQ[8];/* LFO FREQ table */ -#endif -} FM_OPN; - -/* OPN key frequency number -> key code follow table */ -/* fnum higher 4bit -> keycode lower 2bit */ -static const UINT8 OPN_FKTABLE[16]={0,0,0,0,0,0,0,1,2,3,3,3,3,3,3,3}; - -#if FM_LFO_SUPPORT -/* OPN LFO waveform table */ -static INT32 OPN_LFO_wave[LFO_ENT]; -#endif - -static int OPNInitTable(void) -{ - int i; - -#if FM_LFO_SUPPORT - /* LFO wave table */ - for(i=0;iST.freqbase = (OPN->ST.rate) ? ((double)OPN->ST.clock / OPN->ST.rate) / pris : 0; - /* Timer base time */ - OPN->ST.TimerBase = 1.0/((double)OPN->ST.clock / (double)TimerPris); -// /* SSG part priscaler set */ -// if( SSGpris ) SSGClk( OPN->ST.index, OPN->ST.clock * 2 / SSGpris ); - /* make time tables */ - init_timetables( &OPN->ST , OPN_DTTABLE , OPN_ARRATE , OPN_DRRATE ); - /* make fnumber -> increment counter table */ - for( i=0 ; i < 2048 ; i++ ) - { - /* it is freq table for octave 7 */ - /* opn freq counter = 20bit */ - OPN->FN_TABLE[i] = (UINT32)( (double)i * OPN->ST.freqbase * FREQ_RATE * (1<<7) / 2 ); - } -#if FM_LFO_SUPPORT - /* LFO freq. table */ - { - /* 3.98Hz,5.56Hz,6.02Hz,6.37Hz,6.88Hz,9.63Hz,48.1Hz,72.2Hz @ 8MHz */ -#define FM_LF(Hz) ((double)LFO_ENT*(1<LFO_FREQ[i] = (UINT32)(freq_table[i] * OPN->ST.freqbase); - } - } -#endif - -} - -/* ---------- write a OPN mode register 0x20-0x2f ---------- */ -static void OPNWriteMode(FM_OPN *OPN, int r, int v) -{ - UINT8 c; - FM_CH *CH; - - switch(r){ - case 0x21: /* Test */ - break; -#if FM_LFO_SUPPORT - case 0x22: /* LFO FREQ (YM2608/YM2612) */ - if( OPN->type & TYPE_LFOPAN ) - { - OPN->LFOIncr = (v&0x08) ? OPN->LFO_FREQ[v&7] : 0; - cur_chip = NULL; - } - break; -#endif - case 0x24: /* timer A High 8*/ - OPN->ST.TA = (OPN->ST.TA & 0x03)|(((int)v)<<2); - break; - case 0x25: /* timer A Low 2*/ - OPN->ST.TA = (OPN->ST.TA & 0x3fc)|(v&3); - break; - case 0x26: /* timer B */ - OPN->ST.TB = v; - break; - case 0x27: /* mode , timer controll */ - FMSetMode( &(OPN->ST),OPN->ST.index,v ); - break; - case 0x28: /* key on / off */ - c = v&0x03; - if( c == 3 ) break; - if( (v&0x04) && (OPN->type & TYPE_6CH) ) c+=3; - CH = OPN->P_CH; - CH = &CH[c]; - /* csm mode */ - /* if( c == 2 && (OPN->ST.mode & 0x80) ) break; */ - if(v&0x10) FM_KEYON(CH,SLOT1); else FM_KEYOFF(CH,SLOT1); - if(v&0x20) FM_KEYON(CH,SLOT2); else FM_KEYOFF(CH,SLOT2); - if(v&0x40) FM_KEYON(CH,SLOT3); else FM_KEYOFF(CH,SLOT3); - if(v&0x80) FM_KEYON(CH,SLOT4); else FM_KEYOFF(CH,SLOT4); - - break; - } -} - -/* ---------- write a OPN register (0x30-0xff) ---------- */ -static void OPNWriteReg(FM_OPN *OPN, int r, int v) -{ - UINT8 c; - FM_CH *CH; - FM_SLOT *SLOT; - - /* 0x30 - 0xff */ - if( (c = OPN_CHAN(r)) == 3 ) return; /* 0xX3,0xX7,0xXB,0xXF */ - if( (r >= 0x100) /* && (OPN->type & TYPE_6CH) */ ) c+=3; - CH = OPN->P_CH; - CH = &CH[c]; - - SLOT = &(CH->SLOT[OPN_SLOT(r)]); - switch( r & 0xf0 ) { - case 0x30: /* DET , MUL */ - set_det_mul(&OPN->ST,CH,SLOT,v); - break; - case 0x40: /* TL */ - set_tl(CH,SLOT,v,(c == 2) && (OPN->ST.mode & 0x80) ); - break; - case 0x50: /* KS, AR */ - set_ar_ksr(CH,SLOT,v,OPN->ST.AR_TABLE); - break; - case 0x60: /* DR */ - /* bit7 = AMS_ON ENABLE(YM2612) */ - set_dr(SLOT,v,OPN->ST.DR_TABLE); -#if FM_LFO_SUPPORT - if( OPN->type & TYPE_LFOPAN) - { - SLOT->amon = v>>7; - SLOT->ams = CH->ams * SLOT->amon; - } -#endif - break; - case 0x70: /* SR */ - set_sr(SLOT,v,OPN->ST.DR_TABLE); - break; - case 0x80: /* SL, RR */ - set_sl_rr(SLOT,v,OPN->ST.DR_TABLE); - break; - case 0x90: /* SSG-EG */ - SLOT->SEG = v&0x0f; - break; - case 0xa0: - switch( OPN_SLOT(r) ){ - case 0: /* 0xa0-0xa2 : FNUM1 */ - { - UINT32 fn = (((UINT32)( (CH->fn_h)&7))<<8) + v; - UINT8 blk = CH->fn_h>>3; - /* make keyscale code */ - CH->kcode = (blk<<2)|OPN_FKTABLE[(fn>>7)]; - /* make basic increment counter 32bit = 1 cycle */ - CH->fc = OPN->FN_TABLE[fn]>>(7-blk); - CH->SLOT[SLOT1].Incr=-1; - } - break; - case 1: /* 0xa4-0xa6 : FNUM2,BLK */ - CH->fn_h = v&0x3f; - break; - case 2: /* 0xa8-0xaa : 3CH FNUM1 */ - if( r < 0x100) - { - UINT32 fn = (((UINT32)(OPN->SL3.fn_h[c]&7))<<8) + v; - UINT8 blk = OPN->SL3.fn_h[c]>>3; - /* make keyscale code */ - OPN->SL3.kcode[c]= (blk<<2)|OPN_FKTABLE[(fn>>7)]; - /* make basic increment counter 32bit = 1 cycle */ - OPN->SL3.fc[c] = OPN->FN_TABLE[fn]>>(7-blk); - (OPN->P_CH)[2].SLOT[SLOT1].Incr=-1; - } - break; - case 3: /* 0xac-0xae : 3CH FNUM2,BLK */ - if( r < 0x100) - OPN->SL3.fn_h[c] = v&0x3f; - break; - } - break; - case 0xb0: - switch( OPN_SLOT(r) ){ - case 0: /* 0xb0-0xb2 : FB,ALGO */ - { - int feedback = (v>>3)&7; - CH->ALGO = v&7; - CH->FB = feedback ? 8+1 - feedback : 0; - setup_connection( CH ); - } - break; - case 1: /* 0xb4-0xb6 : L , R , AMS , PMS (YM2612/YM2608) */ - if( OPN->type & TYPE_LFOPAN) - { -#if FM_LFO_SUPPORT - /* b0-2 PMS */ - /* 0,3.4,6.7,10,14,20,40,80(cent) */ - static const double pmd_table[8]={0,3.4,6.7,10,14,20,40,80}; - static const int amd_table[4]={(int)(0/EG_STEP),(int)(1.4/EG_STEP),(int)(5.9/EG_STEP),(int)(11.8/EG_STEP) }; - CH->pms = (INT32)( (1.5/1200.0)*pmd_table[v & 7] * PMS_RATE); - /* b4-5 AMS */ - /* 0 , 1.4 , 5.9 , 11.8(dB) */ - CH->ams = amd_table[(v>>4) & 0x03]; - CH->SLOT[SLOT1].ams = CH->ams * CH->SLOT[SLOT1].amon; - CH->SLOT[SLOT2].ams = CH->ams * CH->SLOT[SLOT2].amon; - CH->SLOT[SLOT3].ams = CH->ams * CH->SLOT[SLOT3].amon; - CH->SLOT[SLOT4].ams = CH->ams * CH->SLOT[SLOT4].amon; -#endif - /* PAN */ - CH->PAN = (v>>6)&0x03; /* PAN : b6 = R , b7 = L */ - setup_connection( CH ); - - } - break; - } - break; - } -} -#endif /* BUILD_OPN */ - -#if BUILD_YM2612 -/*******************************************************************************/ -/* YM2612 local section */ -/*******************************************************************************/ -/* here's the virtual YM2612 */ -typedef struct ym2612_f { - FM_OPN OPN; /* OPN state */ - FM_CH CH[6]; /* channel state */ - int address1; /* address register1 */ - /* dac output (YM2612) */ - int dacen; - int dacout; -} YM2612; - -static int YM2612NumChips; /* total chip */ -static YM2612 *FM2612=NULL; /* array of YM2612's */ - -static int dacen; - -/* ---------- update one of chip ----------- */ -void YM2612UpdateOne(int num, INT16 **buffer, int length) -{ - YM2612 *F2612 = &(FM2612[num]); - FM_OPN *OPN = &(FM2612[num].OPN); - int i; - FM_CH *ch,*ech; - FMSAMPLE *bufL,*bufR; - int dacout = F2612->dacout; - - /* set bufer */ - bufL = buffer[0]; - bufR = buffer[1]; - - if( (void *)F2612 != cur_chip ){ - cur_chip = (void *)F2612; - - State = &OPN->ST; - cch[0] = &F2612->CH[0]; - cch[1] = &F2612->CH[1]; - cch[2] = &F2612->CH[2]; - cch[3] = &F2612->CH[3]; - cch[4] = &F2612->CH[4]; - cch[5] = &F2612->CH[5]; - /* DAC mode */ - dacen = F2612->dacen; -#if FM_LFO_SUPPORT - LFOCnt = OPN->LFOCnt; - LFOIncr = OPN->LFOIncr; - if( !LFOIncr ) lfo_amd = lfo_pmd = 0; -#endif - } - /* update frequency counter */ - OPN_CALC_FCOUNT( cch[0] ); - OPN_CALC_FCOUNT( cch[1] ); - if( (State->mode & 0xc0) ){ - /* 3SLOT MODE */ - if( cch[2]->SLOT[SLOT1].Incr==-1){ - /* 3 slot mode */ - CALC_FCSLOT(&cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] ); - CALC_FCSLOT(&cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] ); - CALC_FCSLOT(&cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] ); - CALC_FCSLOT(&cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode ); - } - }else OPN_CALC_FCOUNT( cch[2] ); - OPN_CALC_FCOUNT( cch[3] ); - OPN_CALC_FCOUNT( cch[4] ); - OPN_CALC_FCOUNT( cch[5] ); - - ech = dacen ? cch[4] : cch[5]; - /* buffering */ - for( i=0; i < length ; i++ ) - { -#if FM_LFO_SUPPORT - /* LFO */ - if( LFOIncr ) - { - lfo_amd = OPN_LFO_wave[(LFOCnt+=LFOIncr)>>LFO_SHIFT]; - lfo_pmd = lfo_amd-(LFO_RATE/2); - } -#endif - /* clear output acc. */ - out_ch[OUTD_LEFT] = out_ch[OUTD_RIGHT]= out_ch[OUTD_CENTER] = 0; - /* calcrate channel output */ - for(ch = cch[0] ; ch <= ech ; ch++) - FM_CALC_CH( ch ); - if( dacen ) *cch[5]->connect4 += dacout; - /* buffering */ - FM_BUFFERING_STEREO; - /* timer A controll */ - INTERNAL_TIMER_A( State , cch[2] ) - } - INTERNAL_TIMER_B(State,length) -#if FM_LFO_SUPPORT - OPN->LFOCnt = LFOCnt; -#endif -} - -/* -------------------------- YM2612 ---------------------------------- */ -int YM2612Init(int num, int clock, int rate, - FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler) -{ - int i; - - if (FM2612) return (-1); /* duplicate init. */ - cur_chip = NULL; /* hiro-shi!! */ - - YM2612NumChips = num; - - /* allocate extend state space */ - if( (FM2612 = (YM2612 *)emu_Malloc(sizeof(YM2612) * YM2612NumChips))==NULL) - return (-1); - /* clear */ - memset(FM2612,0,sizeof(YM2612) * YM2612NumChips); - /* allocate total level table (128kb space) */ - if( !OPNInitTable() ) - { - emu_Free( FM2612 ); - return (-1); - } - - for ( i = 0 ; i < YM2612NumChips; i++ ) { - FM2612[i].OPN.ST.index = i; - FM2612[i].OPN.type = TYPE_YM2612; - FM2612[i].OPN.P_CH = FM2612[i].CH; - FM2612[i].OPN.ST.clock = clock; - FM2612[i].OPN.ST.rate = rate; - /* FM2612[i].OPN.ST.irq = 0; */ - /* FM2612[i].OPN.ST.status = 0; */ - FM2612[i].OPN.ST.timermodel = FM_TIMER_INTERVAL; - /* Extend handler */ - FM2612[i].OPN.ST.Timer_Handler = TimerHandler; - FM2612[i].OPN.ST.IRQ_Handler = IRQHandler; - YM2612ResetChip(i); - } - return 0; -} - -/* ---------- shut down emurator ----------- */ -void YM2612Shutdown() -{ - if (!FM2612) return; - - FMCloseTable(); - emu_Free(FM2612); - FM2612 = NULL; -} - -/* ---------- reset one of chip ---------- */ -void YM2612ResetChip(int num) -{ - int i; - YM2612 *F2612 = &(FM2612[num]); - FM_OPN *OPN = &(FM2612[num].OPN); - - OPNSetPris( OPN , 12*12, 12*12, 0); - /* status clear */ - FM_IRQMASK_SET(&OPN->ST,0x03); - OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */ - - reset_channel( &OPN->ST , &F2612->CH[0] , 6 ); - - for(i = 0xb6 ; i >= 0xb4 ; i-- ) - { - OPNWriteReg(OPN,i ,0xc0); - OPNWriteReg(OPN,i|0x100,0xc0); - } - for(i = 0xb2 ; i >= 0x30 ; i-- ) - { - OPNWriteReg(OPN,i ,0); - OPNWriteReg(OPN,i|0x100,0); - } - for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(OPN,i,0); - /* DAC mode clear */ - F2612->dacen = 0; -} - -/* YM2612 write */ -/* n = number */ -/* a = address */ -/* v = value */ -int YM2612Write(int n, int a,UINT8 v) -{ - YM2612 *F2612 = &(FM2612[n]); - int addr; - - switch( a&3){ - case 0: /* address port 0 */ - F2612->OPN.ST.address = v & 0xff; - break; - case 1: /* data port 0 */ - addr = F2612->OPN.ST.address; - switch( addr & 0xf0 ) - { - case 0x20: /* 0x20-0x2f Mode */ - switch( addr ) - { - case 0x2a: /* DAC data (YM2612) */ - F2612->dacout = ((int)v - 0x80)<<(TL_BITS-7); - F2612->dacout = ((int)(v/2)-0x80)<<(TL_BITS-7); - break; - case 0x2b: /* DAC Sel (YM2612) */ - /* b7 = dac enable */ - F2612->dacen = v & 0x80; - cur_chip = NULL; - break; - default: /* OPN section */ - /* write register */ - OPNWriteMode(&(F2612->OPN),addr,v); - } - break; - default: /* 0x30-0xff OPN section */ - /* write register */ - OPNWriteReg(&(F2612->OPN),addr,v); - } - break; - case 2: /* address port 1 */ - F2612->address1 = v & 0xff; - break; - case 3: /* data port 1 */ - addr = F2612->address1; - OPNWriteReg(&(F2612->OPN),addr|0x100,v); - break; - } - return F2612->OPN.ST.irq; -} -UINT8 YM2612Read(int n,int a) -{ - YM2612 *F2612 = &(FM2612[n]); - - switch( a&3){ - case 0: /* status 0 */ - return F2612->OPN.ST.status; - case 1: - case 2: - case 3: - return F2612->OPN.ST.status; - } - return 0; -} - -int YM2612TimerOver(int n,int c) -{ - YM2612 *F2612 = &(FM2612[n]); - - if( c ) - { /* Timer B */ - TimerBOver( &(F2612->OPN.ST) ); - } - else - { /* Timer A */ - /* timer update */ - TimerAOver( &(F2612->OPN.ST) ); - /* CSM mode key,TL controll */ - if( F2612->OPN.ST.mode & 0x80 ) - { /* CSM mode total level latch and auto key on */ - CSMKeyControll( &(F2612->CH[2]) ); - } - } - return F2612->OPN.ST.irq; -} - -#endif /* BUILD_YM2612 */ + +#include "shared.h" +#include + +#ifndef PI +#define PI 3.14159265358979323846 +#endif + +#define BUILD_OPN (BUILD_YM2612) +#define BUILD_STEREO (BUILD_YM2612) +#define BUILD_LFO (BUILD_YM2612) + +#define SIN_ENT 2048 +#define ENV_BITS 16 +#define EG_ENT 4096 +#define EG_STEP (96.0/EG_ENT) /* OPL == 0.1875 dB */ + +#if FM_LFO_SUPPORT +/* LFO table entries */ +#define LFO_ENT 512 +#define LFO_SHIFT (32-9) +#define LFO_RATE 0x10000 +#endif + +/* -------------------- preliminary define section --------------------- */ +/* attack/decay rate time rate */ +#define OPM_ARRATE 399128 +#define OPM_DRRATE 5514396 +/* It is not checked , because I haven't YM2203 rate */ +#define OPN_ARRATE OPM_ARRATE +#define OPN_DRRATE OPM_DRRATE + +/* PG output cut off level : 78dB(14bit)? */ +#define PG_CUT_OFF ((int)(78.0/EG_STEP)) +/* EG output cut off level : 68dB? */ +#define EG_CUT_OFF ((int)(68.0/EG_STEP)) + +#define FREQ_BITS 24 /* frequency turn */ + +/* PG counter is 21bits @oct.7 */ +#define FREQ_RATE (1<<(FREQ_BITS-21)) +#define TL_BITS (FREQ_BITS+2) +/* OPbit = 14(13+sign) : TL_BITS+1(sign) / output = 16bit */ +#define TL_SHIFT (TL_BITS+1-(14-16)) + +/* output final shift */ +#define FM_OUTSB (TL_SHIFT-FM_OUTPUT_BIT) +#define FM_MAXOUT ((1<<(TL_SHIFT-1))-1) +#define FM_MINOUT (-(1<<(TL_SHIFT-1))) + +/* -------------------- local defines , macros --------------------- */ + +/* envelope counter position */ +#define EG_AST 0 /* start of Attack phase */ +#define EG_AED (EG_ENT<>2)&3) +#define OPM_CHAN(N) (N&7) +#define OPM_SLOT(N) ((N>>3)&3) +/* slot number */ +#define SLOT1 0 +#define SLOT2 2 +#define SLOT3 1 +#define SLOT4 3 + +/* bit0 = Right enable , bit1 = Left enable */ +#define OUTD_RIGHT 1 +#define OUTD_LEFT 2 +#define OUTD_CENTER 3 + +/* FM timer model */ +#define FM_TIMER_SINGLE (0) +#define FM_TIMER_INTERVAL (1) + +/* ---------- OPN / OPM one channel ---------- */ +typedef struct fm_slot { + INT32 *DT; /* detune :DT_TABLE[DT] */ + int DT2; /* multiple,Detune2:(DT2<<4)|ML for OPM*/ + int TL; /* total level :TL << 8 */ + UINT8 KSR; /* key scale rate :3-KSR */ + const INT32 *AR; /* attack rate :&AR_TABLE[AR<<1] */ + const INT32 *DR; /* decay rate :&DR_TABLE[DR<<1] */ + const INT32 *SR; /* sustin rate :&DR_TABLE[SR<<1] */ + int SL; /* sustin level :SL_TABLE[SL] */ + const INT32 *RR; /* release rate :&DR_TABLE[RR<<2+2] */ + UINT8 SEG; /* SSG EG type :SSGEG */ + UINT8 ksr; /* key scale rate :kcode>>(3-KSR) */ + UINT32 mul; /* multiple :ML_TABLE[ML] */ + /* Phase Generator */ + UINT32 Cnt; /* frequency count : */ + UINT32 Incr; /* frequency step : */ + /* Envelope Generator */ + void (*eg_next)(struct fm_slot *SLOT); /* pointer of phase handler */ + INT32 evc; /* envelope counter */ + INT32 eve; /* envelope counter end point */ + INT32 evs; /* envelope counter step */ + INT32 evsa; /* envelope step for Attack */ + INT32 evsd; /* envelope step for Decay */ + INT32 evss; /* envelope step for Sustain */ + INT32 evsr; /* envelope step for Release */ + INT32 TLL; /* adjusted TotalLevel */ + /* LFO */ + UINT8 amon; /* AMS enable flag */ + UINT32 ams; /* AMS depth level of this SLOT */ +}FM_SLOT; + +typedef struct fm_chan { + FM_SLOT SLOT[4]; + UINT8 PAN; /* PAN :NONE,LEFT,RIGHT or CENTER */ + UINT8 ALGO; /* Algorythm */ + UINT8 FB; /* shift count of self feed back */ + INT32 op1_out[2]; /* op1 output for beedback */ + /* Algorythm (connection) */ + INT32 *connect1; /* pointer of SLOT1 output */ + INT32 *connect2; /* pointer of SLOT2 output */ + INT32 *connect3; /* pointer of SLOT3 output */ + INT32 *connect4; /* pointer of SLOT4 output */ + /* LFO */ + INT32 pms; /* PMS depth level of channel */ + UINT32 ams; /* AMS depth level of channel */ + /* Phase Generator */ + UINT32 fc; /* fnum,blk :adjusted to sampling rate */ + UINT8 fn_h; /* freq latch : */ + UINT8 kcode; /* key code : */ +} FM_CH; + +/* OPN/OPM common state */ +typedef struct fm_state { + UINT8 index; /* chip index (number of chip) */ + int clock; /* master clock (Hz) */ + int rate; /* sampling rate (Hz) */ + double freqbase; /* frequency base */ + double TimerBase; /* Timer base time */ + UINT8 address; /* address register */ + UINT8 irq; /* interrupt level */ + UINT8 irqmask; /* irq mask */ + UINT8 status; /* status flag */ + UINT32 mode; /* mode CSM / 3SLOT */ + int TA; /* timer a */ + int TAC; /* timer a counter */ + UINT8 TB; /* timer b */ + int TBC; /* timer b counter */ + /* speedup customize */ + /* local time tables */ + INT32 DT_TABLE[8][32]; /* DeTune tables */ + INT32 AR_TABLE[94]; /* Atttack rate tables */ + INT32 DR_TABLE[94]; /* Decay rate tables */ + /* Extention Timer and IRQ handler */ + FM_TIMERHANDLER Timer_Handler; + FM_IRQHANDLER IRQ_Handler; + /* timer model single / interval */ + UINT8 timermodel; +}FM_ST; + +/* -------------------- tables --------------------- */ + +/* sustain lebel table (3db per step) */ +/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ +#define SC(db) (int)((db*((3/EG_STEP)*(1< max ) val = max; \ + else if ( val < min ) val = min; \ +} + +/* ----- buffering one of data(STEREO chip) ----- */ +#if FM_STEREO_MIX +/* stereo mixing */ +#define FM_BUFFERING_STEREO \ +{ \ + /* get left & right output with clipping */ \ + out_ch[OUTD_LEFT] += out_ch[OUTD_CENTER]; \ + Limit( out_ch[OUTD_LEFT] , FM_MAXOUT, FM_MINOUT ); \ + out_ch[OUTD_RIGHT] += out_ch[OUTD_CENTER]; \ + Limit( out_ch[OUTD_RIGHT], FM_MAXOUT, FM_MINOUT ); \ + /* buffering */ \ + *bufL++ = out_ch[OUTD_LEFT] >>FM_OUTSB; \ + *bufL++ = out_ch[OUTD_RIGHT]>>FM_OUTSB; \ +} +#else +/* stereo separate */ +#define FM_BUFFERING_STEREO \ +{ \ + /* get left & right output with clipping */ \ + out_ch[OUTD_LEFT] += out_ch[OUTD_CENTER]; \ + Limit( out_ch[OUTD_LEFT] , FM_MAXOUT, FM_MINOUT ); \ + out_ch[OUTD_RIGHT] += out_ch[OUTD_CENTER]; \ + Limit( out_ch[OUTD_RIGHT], FM_MAXOUT, FM_MINOUT ); \ + /* buffering */ \ + bufL[i] = out_ch[OUTD_LEFT] >>FM_OUTSB; \ + bufR[i] = out_ch[OUTD_RIGHT]>>FM_OUTSB; \ +} +#endif + +#if FM_INTERNAL_TIMER +/* ----- internal timer mode , update timer */ +/* ---------- calcrate timer A ---------- */ +#define INTERNAL_TIMER_A(ST,CSM_CH) \ +{ \ + if( ST->TAC && (ST->Timer_Handler==0) ) \ + if( (ST->TAC -= (int)(ST->freqbase*4096)) <= 0 ) \ + { \ + TimerAOver( ST ); \ + /* CSM mode total level latch and auto key on */ \ + if( ST->mode & 0x80 ) \ + CSMKeyControll( CSM_CH ); \ + } \ +} +/* ---------- calcrate timer B ---------- */ +#define INTERNAL_TIMER_B(ST,step) \ +{ \ + if( ST->TBC && (ST->Timer_Handler==0) ) \ + if( (ST->TBC -= (int)(ST->freqbase*4096*step)) <= 0 ) \ + TimerBOver( ST ); \ +} +#else /* FM_INTERNAL_TIMER */ +/* external timer mode */ +#define INTERNAL_TIMER_A(ST,CSM_CH) +#define INTERNAL_TIMER_B(ST,step) +#endif /* FM_INTERNAL_TIMER */ + +/* --------------------- subroutines --------------------- */ +/* status set and IRQ handling */ +static __inline__ void FM_STATUS_SET(FM_ST *ST,int flag) +{ + /* set status flag */ + ST->status |= flag; + if ( !(ST->irq) && (ST->status & ST->irqmask) ) + { + ST->irq = 1; + /* callback user interrupt handler (IRQ is OFF to ON) */ + if(ST->IRQ_Handler) (ST->IRQ_Handler)(ST->index,1); + } +} + +/* status reset and IRQ handling */ +static __inline__ void FM_STATUS_RESET(FM_ST *ST,int flag) +{ + /* reset status flag */ + ST->status &=~flag; + if ( (ST->irq) && !(ST->status & ST->irqmask) ) + { + ST->irq = 0; + /* callback user interrupt handler (IRQ is ON to OFF) */ + if(ST->IRQ_Handler) (ST->IRQ_Handler)(ST->index,0); + } +} + +/* IRQ mask set */ +static __inline__ void FM_IRQMASK_SET(FM_ST *ST,int flag) +{ + ST->irqmask = flag; + /* IRQ handling check */ + FM_STATUS_SET(ST,0); + FM_STATUS_RESET(ST,0); +} + +/* ---------- event hander of Phase Generator ---------- */ + +/* Release end -> stop counter */ +static void FM_EG_Release( FM_SLOT *SLOT ) +{ + SLOT->evc = EG_OFF; + SLOT->eve = EG_OFF+1; + SLOT->evs = 0; +} + +/* SUSTAIN end -> stop counter */ +static void FM_EG_SR( FM_SLOT *SLOT ) +{ + SLOT->evs = 0; + SLOT->evc = EG_OFF; + SLOT->eve = EG_OFF+1; +} + +/* Decay end -> Sustain */ +static void FM_EG_DR( FM_SLOT *SLOT ) +{ + SLOT->eg_next = FM_EG_SR; + SLOT->evc = SLOT->SL; + SLOT->eve = EG_DED; + SLOT->evs = SLOT->evss; +} + +/* Attack end -> Decay */ +static void FM_EG_AR( FM_SLOT *SLOT ) +{ + /* next DR */ + SLOT->eg_next = FM_EG_DR; + SLOT->evc = EG_DST; + SLOT->eve = SLOT->SL; + SLOT->evs = SLOT->evsd; +} + +#if FM_SEG_SUPPORT +static void FM_EG_SSG_SR( FM_SLOT *SLOT ); + +/* SEG down side end */ +static void FM_EG_SSG_DR( FM_SLOT *SLOT ) +{ + if( SLOT->SEG&2){ + /* reverce */ + SLOT->eg_next = FM_EG_SSG_SR; + SLOT->evc = SLOT->SL + (EG_UST - EG_DST); + SLOT->eve = EG_UED; + SLOT->evs = SLOT->evss; + }else{ + /* again */ + SLOT->evc = EG_DST; + } + /* hold */ + if( SLOT->SEG&1) SLOT->evs = 0; +} + +/* SEG upside side end */ +static void FM_EG_SSG_SR( FM_SLOT *SLOT ) +{ + if( SLOT->SEG&2){ + /* reverce */ + SLOT->eg_next = FM_EG_SSG_DR; + SLOT->evc = EG_DST; + SLOT->eve = EG_DED; + SLOT->evs = SLOT->evsd; + }else{ + /* again */ + SLOT->evc = SLOT->SL + (EG_UST - EG_DST); + } + /* hold check */ + if( SLOT->SEG&1) SLOT->evs = 0; +} + +/* SEG Attack end */ +static void FM_EG_SSG_AR( FM_SLOT *SLOT ) +{ + if( SLOT->SEG&4){ /* start direction */ + /* next SSG-SR (upside start ) */ + SLOT->eg_next = FM_EG_SSG_SR; + SLOT->evc = SLOT->SL + (EG_UST - EG_DST); + SLOT->eve = EG_UED; + SLOT->evs = SLOT->evss; + }else{ + /* next SSG-DR (downside start ) */ + SLOT->eg_next = FM_EG_SSG_DR; + SLOT->evc = EG_DST; + SLOT->eve = EG_DED; + SLOT->evs = SLOT->evsd; + } +} +#endif /* FM_SEG_SUPPORT */ + +/* ----- key on of SLOT ----- */ +#define FM_KEY_IS(SLOT) ((SLOT)->eg_next!=FM_EG_Release) + +static __inline__ void FM_KEYON(FM_CH *CH , int s ) +{ + FM_SLOT *SLOT = &CH->SLOT[s]; + if( !FM_KEY_IS(SLOT) ) + { + /* restart Phage Generator */ + SLOT->Cnt = 0; + /* phase -> Attack */ +#if FM_SEG_SUPPORT + if( SLOT->SEG&8 ) SLOT->eg_next = FM_EG_SSG_AR; + else +#endif + SLOT->eg_next = FM_EG_AR; + SLOT->evs = SLOT->evsa; +#if 0 + /* convert decay count to attack count */ + /* --- This caused the problem by credit sound of paper boy. --- */ + SLOT->evc = EG_AST + DRAR_TABLE[ENV_CURVE[SLOT->evc>>ENV_BITS]];/* + SLOT->evs;*/ +#else + /* reset attack counter */ + SLOT->evc = EG_AST; +#endif + SLOT->eve = EG_AED; + } +} +/* ----- key off of SLOT ----- */ +static __inline__ void FM_KEYOFF(FM_CH *CH , int s ) +{ + FM_SLOT *SLOT = &CH->SLOT[s]; + if( FM_KEY_IS(SLOT) ) + { + /* if Attack phase then adjust envelope counter */ + if( SLOT->evc < EG_DST ) + SLOT->evc = (ENV_CURVE[SLOT->evc>>ENV_BITS]< Release */ + SLOT->eg_next = FM_EG_Release; + SLOT->eve = EG_DED; + SLOT->evs = SLOT->evsr; + } +} + +/* setup Algorythm and PAN connection */ +static void setup_connection( FM_CH *CH ) +{ + INT32 *carrier = &out_ch[CH->PAN]; /* NONE,LEFT,RIGHT or CENTER */ + + switch( CH->ALGO ){ + case 0: + /* PG---S1---S2---S3---S4---OUT */ + CH->connect1 = &pg_in2; + CH->connect2 = &pg_in3; + CH->connect3 = &pg_in4; + break; + case 1: + /* PG---S1-+-S3---S4---OUT */ + /* PG---S2-+ */ + CH->connect1 = &pg_in3; + CH->connect2 = &pg_in3; + CH->connect3 = &pg_in4; + break; + case 2: + /* PG---S1------+-S4---OUT */ + /* PG---S2---S3-+ */ + CH->connect1 = &pg_in4; + CH->connect2 = &pg_in3; + CH->connect3 = &pg_in4; + break; + case 3: + /* PG---S1---S2-+-S4---OUT */ + /* PG---S3------+ */ + CH->connect1 = &pg_in2; + CH->connect2 = &pg_in4; + CH->connect3 = &pg_in4; + break; + case 4: + /* PG---S1---S2-+--OUT */ + /* PG---S3---S4-+ */ + CH->connect1 = &pg_in2; + CH->connect2 = carrier; + CH->connect3 = &pg_in4; + break; + case 5: + /* +-S2-+ */ + /* PG---S1-+-S3-+-OUT */ + /* +-S4-+ */ + CH->connect1 = 0; /* special case */ + CH->connect2 = carrier; + CH->connect3 = carrier; + break; + case 6: + /* PG---S1---S2-+ */ + /* PG--------S3-+-OUT */ + /* PG--------S4-+ */ + CH->connect1 = &pg_in2; + CH->connect2 = carrier; + CH->connect3 = carrier; + break; + case 7: + /* PG---S1-+ */ + /* PG---S2-+-OUT */ + /* PG---S3-+ */ + /* PG---S4-+ */ + CH->connect1 = carrier; + CH->connect2 = carrier; + CH->connect3 = carrier; + } + CH->connect4 = carrier; +} + +/* set detune & multiple */ +static __inline__ void set_det_mul(FM_ST *ST,FM_CH *CH,FM_SLOT *SLOT,int v) +{ + SLOT->mul = MUL_TABLE[v&0x0f]; + SLOT->DT = ST->DT_TABLE[(v>>4)&7]; + CH->SLOT[SLOT1].Incr=-1; +} + +/* set total level */ +static __inline__ void set_tl(FM_CH *CH,FM_SLOT *SLOT , int v,int csmflag) +{ + v &= 0x7f; + v = (v<<7)|v; /* 7bit -> 14bit */ + SLOT->TL = (v*EG_ENT)>>14; + /* if it is not a CSM channel , latch the total level */ + if( !csmflag ) + SLOT->TLL = SLOT->TL; +} + +/* set attack rate & key scale */ +static __inline__ void set_ar_ksr(FM_CH *CH,FM_SLOT *SLOT,int v,INT32 *ar_table) +{ + SLOT->KSR = 3-(v>>6); + SLOT->AR = (v&=0x1f) ? &ar_table[v<<1] : RATE_0; + SLOT->evsa = SLOT->AR[SLOT->ksr]; + if( SLOT->eg_next == FM_EG_AR ) SLOT->evs = SLOT->evsa; + CH->SLOT[SLOT1].Incr=-1; +} +/* set decay rate */ +static __inline__ void set_dr(FM_SLOT *SLOT,int v,INT32 *dr_table) +{ + SLOT->DR = (v&=0x1f) ? &dr_table[v<<1] : RATE_0; + SLOT->evsd = SLOT->DR[SLOT->ksr]; + if( SLOT->eg_next == FM_EG_DR ) SLOT->evs = SLOT->evsd; +} +/* set sustain rate */ +static __inline__ void set_sr(FM_SLOT *SLOT,int v,INT32 *dr_table) +{ + SLOT->SR = (v&=0x1f) ? &dr_table[v<<1] : RATE_0; + SLOT->evss = SLOT->SR[SLOT->ksr]; + if( SLOT->eg_next == FM_EG_SR ) SLOT->evs = SLOT->evss; +} +/* set release rate */ +static __inline__ void set_sl_rr(FM_SLOT *SLOT,int v,INT32 *dr_table) +{ + SLOT->SL = SL_TABLE[(v>>4)]; + SLOT->RR = &dr_table[((v&0x0f)<<2)|2]; + SLOT->evsr = SLOT->RR[SLOT->ksr]; + if( SLOT->eg_next == FM_EG_Release ) SLOT->evs = SLOT->evsr; +} + +/* operator output calcrator */ +#define OP_OUT(PG,EG) SIN_TABLE[(PG/(0x1000000/SIN_ENT))&(SIN_ENT-1)][EG] +#define OP_OUTN(PG,EG) NOISE_TABLE[(PG/(0x1000000/SIN_ENT))&(SIN_ENT-1)][EG] + +/* eg calcration */ +#if FM_LFO_SUPPORT +#define FM_CALC_EG(OUT,SLOT) \ +{ \ + if( (SLOT.evc += SLOT.evs) >= SLOT.eve) \ + SLOT.eg_next(&(SLOT)); \ + OUT = SLOT.TLL+ENV_CURVE[SLOT.evc>>ENV_BITS]; \ + if(SLOT.ams) \ + OUT += (SLOT.ams*lfo_amd/LFO_RATE); \ +} +#else +#define FM_CALC_EG(OUT,SLOT) \ +{ \ + if( (SLOT.evc += SLOT.evs) >= SLOT.eve) \ + SLOT.eg_next(&(SLOT)); \ + OUT = SLOT.TLL+ENV_CURVE[SLOT.evc>>ENV_BITS]; \ +} +#endif + +/* ---------- calcrate one of channel ---------- */ +static __inline__ void FM_CALC_CH( FM_CH *CH ) +{ + UINT32 eg_out1,eg_out2,eg_out3,eg_out4; //envelope output + + /* Phase Generator */ +#if FM_LFO_SUPPORT + INT32 pms = lfo_pmd * CH->pms / LFO_RATE; + if(pms) + { + pg_in1 = (CH->SLOT[SLOT1].Cnt += CH->SLOT[SLOT1].Incr + (INT32)(pms * CH->SLOT[SLOT1].Incr) / PMS_RATE); + pg_in2 = (CH->SLOT[SLOT2].Cnt += CH->SLOT[SLOT2].Incr + (INT32)(pms * CH->SLOT[SLOT2].Incr) / PMS_RATE); + pg_in3 = (CH->SLOT[SLOT3].Cnt += CH->SLOT[SLOT3].Incr + (INT32)(pms * CH->SLOT[SLOT3].Incr) / PMS_RATE); + pg_in4 = (CH->SLOT[SLOT4].Cnt += CH->SLOT[SLOT4].Incr + (INT32)(pms * CH->SLOT[SLOT4].Incr) / PMS_RATE); + } + else +#endif + { + pg_in1 = (CH->SLOT[SLOT1].Cnt += CH->SLOT[SLOT1].Incr); + pg_in2 = (CH->SLOT[SLOT2].Cnt += CH->SLOT[SLOT2].Incr); + pg_in3 = (CH->SLOT[SLOT3].Cnt += CH->SLOT[SLOT3].Incr); + pg_in4 = (CH->SLOT[SLOT4].Cnt += CH->SLOT[SLOT4].Incr); + } + + /* Envelope Generator */ + FM_CALC_EG(eg_out1,CH->SLOT[SLOT1]); + FM_CALC_EG(eg_out2,CH->SLOT[SLOT2]); + FM_CALC_EG(eg_out3,CH->SLOT[SLOT3]); + FM_CALC_EG(eg_out4,CH->SLOT[SLOT4]); + + /* Connection */ + if( eg_out1 < EG_CUT_OFF ) /* SLOT 1 */ + { + if( CH->FB ){ + /* with self feed back */ + pg_in1 += (CH->op1_out[0]+CH->op1_out[1])>>CH->FB; + CH->op1_out[1] = CH->op1_out[0]; + } + CH->op1_out[0] = OP_OUT(pg_in1,eg_out1); + /* output slot1 */ + if( !CH->connect1 ) + { + /* algorythm 5 */ + pg_in2 += CH->op1_out[0]; + pg_in3 += CH->op1_out[0]; + pg_in4 += CH->op1_out[0]; + }else{ + /* other algorythm */ + *CH->connect1 += CH->op1_out[0]; + } + } + if( eg_out2 < EG_CUT_OFF ) /* SLOT 2 */ + *CH->connect2 += OP_OUT(pg_in2,eg_out2); + if( eg_out3 < EG_CUT_OFF ) /* SLOT 3 */ + *CH->connect3 += OP_OUT(pg_in3,eg_out3); + if( eg_out4 < EG_CUT_OFF ) /* SLOT 4 */ + *CH->connect4 += OP_OUT(pg_in4,eg_out4); +} +/* ---------- frequency counter for operater update ---------- */ +static __inline__ void CALC_FCSLOT(FM_SLOT *SLOT , int fc , int kc ) +{ + int ksr; + + /* frequency step counter */ + SLOT->Incr= (fc+SLOT->DT[kc])*SLOT->mul; /* verified on real chip */ + /* SLOT->Incr= fc*SLOT->mul + SLOT->DT[kc]; */ + ksr = kc >> SLOT->KSR; + if( SLOT->ksr != ksr ) + { + SLOT->ksr = ksr; + /* attack , decay rate recalcration */ + SLOT->evsa = SLOT->AR[ksr]; + SLOT->evsd = SLOT->DR[ksr]; + SLOT->evss = SLOT->SR[ksr]; + SLOT->evsr = SLOT->RR[ksr]; + } +} + +/* ---------- frequency counter ---------- */ +static __inline__ void OPN_CALC_FCOUNT(FM_CH *CH ) +{ + if( CH->SLOT[SLOT1].Incr==-1){ + int fc = CH->fc; + int kc = CH->kcode; + CALC_FCSLOT(&CH->SLOT[SLOT1] , fc , kc ); + CALC_FCSLOT(&CH->SLOT[SLOT2] , fc , kc ); + CALC_FCSLOT(&CH->SLOT[SLOT3] , fc , kc ); + CALC_FCSLOT(&CH->SLOT[SLOT4] , fc , kc ); + } +} + +/* ----------- initialize time tabls ----------- */ +static void init_timetables( FM_ST *ST , UINT8 *DTTABLE , int ARRATE , int DRRATE ) +{ + int i,d; + double rate; + + /* DeTune table */ + for (d = 0;d <= 3;d++){ + for (i = 0;i <= 31;i++){ + rate = (double)DTTABLE[d*32 + i] * ST->freqbase * FREQ_RATE; + ST->DT_TABLE[d][i] = (INT32) rate; + ST->DT_TABLE[d+4][i] = (INT32)-rate; + } + } + /* make Attack & Decay tables */ + for (i = 0;i < 4;i++) ST->AR_TABLE[i] = ST->DR_TABLE[i] = 0; + for (i = 4;i < 64;i++){ + rate = ST->freqbase; /* frequency rate */ + if( i < 60 ) rate *= 1.0+(i&3)*0.25; /* b0-1 : x1 , x1.25 , x1.5 , x1.75 */ + rate *= 1<<((i>>2)-1); /* b2-5 : shift bit */ + rate *= (double)(EG_ENT<AR_TABLE[i] = (INT32)(rate / ARRATE); + ST->DR_TABLE[i] = (INT32)(rate / DRRATE); + } + ST->AR_TABLE[62] = EG_AED; + ST->AR_TABLE[63] = EG_AED; + for (i = 64;i < 94 ;i++){ /* make for overflow area */ + ST->AR_TABLE[i] = ST->AR_TABLE[63]; + ST->DR_TABLE[i] = ST->DR_TABLE[63]; + } + +} + +/* ---------- reset one of channel ---------- */ +static void reset_channel( FM_ST *ST , FM_CH *CH , int chan ) +{ + int c,s; + + ST->mode = 0; /* normal mode */ + FM_STATUS_RESET(ST,0xff); + ST->TA = 0; + ST->TAC = 0; + ST->TB = 0; + ST->TBC = 0; + + for( c = 0 ; c < chan ; c++ ) + { + CH[c].fc = 0; + CH[c].PAN = OUTD_CENTER; + for(s = 0 ; s < 4 ; s++ ) + { + CH[c].SLOT[s].SEG = 0; + CH[c].SLOT[s].eg_next= FM_EG_Release; + CH[c].SLOT[s].evc = EG_OFF; + CH[c].SLOT[s].eve = EG_OFF+1; + CH[c].SLOT[s].evs = 0; + } + } +} + + +/* ---------- generic table initialize ---------- */ +static int FMInitTable( void ) +{ + int s,t; + double rate; + int i,j; + double pom; + + /* allocate total level table plus+minus section */ + TL_TABLE = (INT32 *)emu_Malloc(2*TL_MAX*sizeof(int)); + if( TL_TABLE == 0 ) return 0; + /* make total level table */ + for (t = 0;t < TL_MAX ;t++){ + if(t >= PG_CUT_OFF) + rate = 0; /* under cut off area */ + else + rate = ((1< voltage */ + TL_TABLE[ t] = (int)rate; + TL_TABLE[TL_MAX+t] = -TL_TABLE[t]; + } + + /* make sinwave table (pointer of total level) */ + for (s = 1;s <= SIN_ENT/4;s++){ + pom = sin(2.0*PI*s/SIN_ENT); /* sin */ + pom = 20*log10(1/pom); /* -> decibel */ + j = (int)(pom / EG_STEP); /* TL_TABLE steps */ + /* cut off check */ + if(j > PG_CUT_OFF) + j = PG_CUT_OFF; + /* degree 0 - 90 , degree 180 - 90 : plus section */ + SIN_TABLE[ s] = SIN_TABLE[SIN_ENT/2-s] = &TL_TABLE[j]; + /* degree 180 - 270 , degree 360 - 270 : minus section */ + SIN_TABLE[SIN_ENT/2+s] = SIN_TABLE[SIN_ENT -s] = &TL_TABLE[TL_MAX+j]; + + } + /* degree 0 = degree 180 = off */ + SIN_TABLE[0] = SIN_TABLE[SIN_ENT/2] = &TL_TABLE[PG_CUT_OFF]; + + /* envelope counter -> envelope output table */ + for (i=0; i= EG_ENT ) pom = EG_ENT-1; */ + ENV_CURVE[i] = (int)pom; + /* DECAY ,RELEASE curve */ + ENV_CURVE[(EG_DST>>ENV_BITS)+i]= i; +#if FM_SEG_SUPPORT + /* DECAY UPSIDE (SSG ENV) */ + ENV_CURVE[(EG_UST>>ENV_BITS)+i]= EG_ENT-1-i; +#endif + } + /* off */ + ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1; + + /* decay to reattack envelope converttable */ + j = EG_ENT-1; + for (i=0; imode = v; + + /* reset Timer b flag */ + if( v & 0x20 ) + FM_STATUS_RESET(ST,0x02); + /* reset Timer a flag */ + if( v & 0x10 ) + FM_STATUS_RESET(ST,0x01); + /* load b */ + if( v & 0x02 ) + { + if( ST->TBC == 0 ) + { + ST->TBC = ( 256-ST->TB)<<4; + /* External timer handler */ + if (ST->Timer_Handler) (ST->Timer_Handler)(n,1,ST->TBC,ST->TimerBase); + } + }else if (ST->timermodel == FM_TIMER_INTERVAL) + { /* stop interbval timer */ + if( ST->TBC != 0 ) + { + ST->TBC = 0; + if (ST->Timer_Handler) (ST->Timer_Handler)(n,1,0,ST->TimerBase); + } + } + /* load a */ + if( v & 0x01 ) + { + if( ST->TAC == 0 ) + { + ST->TAC = (1024-ST->TA); + /* External timer handler */ + if (ST->Timer_Handler) (ST->Timer_Handler)(n,0,ST->TAC,ST->TimerBase); + } + }else if (ST->timermodel == FM_TIMER_INTERVAL) + { /* stop interbval timer */ + if( ST->TAC != 0 ) + { + ST->TAC = 0; + if (ST->Timer_Handler) (ST->Timer_Handler)(n,0,0,ST->TimerBase); + } + } +} + +/* Timer A Overflow */ +static __inline__ void TimerAOver(FM_ST *ST) +{ + /* status set if enabled */ + if(ST->mode & 0x04) FM_STATUS_SET(ST,0x01); + /* clear or reload the counter */ + if (ST->timermodel == FM_TIMER_INTERVAL) + { + ST->TAC = (1024-ST->TA); + if (ST->Timer_Handler) (ST->Timer_Handler)(ST->index,0,ST->TAC,ST->TimerBase); + } + else ST->TAC = 0; +} +/* Timer B Overflow */ +static __inline__ void TimerBOver(FM_ST *ST) +{ + /* status set if enabled */ + if(ST->mode & 0x08) FM_STATUS_SET(ST,0x02); + /* clear or reload the counter */ + if (ST->timermodel == FM_TIMER_INTERVAL) + { + ST->TBC = ( 256-ST->TB)<<4; + if (ST->Timer_Handler) (ST->Timer_Handler)(ST->index,1,ST->TBC,ST->TimerBase); + } + else ST->TBC = 0; +} +/* CSM Key Controll */ +static __inline__ void CSMKeyControll(FM_CH *CH) +{ + /* all key off */ + /* FM_KEYOFF(CH,SLOT1); */ + /* FM_KEYOFF(CH,SLOT2); */ + /* FM_KEYOFF(CH,SLOT3); */ + /* FM_KEYOFF(CH,SLOT4); */ + /* total level latch */ + CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL; + CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL; + CH->SLOT[SLOT3].TLL = CH->SLOT[SLOT3].TL; + CH->SLOT[SLOT4].TLL = CH->SLOT[SLOT4].TL; + /* all key on */ + FM_KEYON(CH,SLOT1); + FM_KEYON(CH,SLOT2); + FM_KEYON(CH,SLOT3); + FM_KEYON(CH,SLOT4); +} + +#if BUILD_OPN +/***********************************************************/ +/* OPN unit */ +/***********************************************************/ + +/* OPN 3slot struct */ +typedef struct opn_3slot { + UINT32 fc[3]; /* fnum3,blk3 :calcrated */ + UINT8 fn_h[3]; /* freq3 latch */ + UINT8 kcode[3]; /* key code : */ +}FM_3SLOT; + +/* OPN/A/B common state */ +typedef struct opn_f { + UINT8 type; /* chip type */ + FM_ST ST; /* general state */ + FM_3SLOT SL3; /* 3 slot mode state */ + FM_CH *P_CH; /* pointer of CH */ + UINT32 FN_TABLE[2048]; /* fnumber -> increment counter */ +#if FM_LFO_SUPPORT + /* LFO */ + UINT32 LFOCnt; + UINT32 LFOIncr; + UINT32 LFO_FREQ[8];/* LFO FREQ table */ +#endif +} FM_OPN; + +/* OPN key frequency number -> key code follow table */ +/* fnum higher 4bit -> keycode lower 2bit */ +static const UINT8 OPN_FKTABLE[16]={0,0,0,0,0,0,0,1,2,3,3,3,3,3,3,3}; + +#if FM_LFO_SUPPORT +/* OPN LFO waveform table */ +static INT32 OPN_LFO_wave[LFO_ENT]; +#endif + +static int OPNInitTable(void) +{ + int i; + +#if FM_LFO_SUPPORT + /* LFO wave table */ + for(i=0;iST.freqbase = (OPN->ST.rate) ? ((double)OPN->ST.clock / OPN->ST.rate) / pris : 0; + /* Timer base time */ + OPN->ST.TimerBase = 1.0/((double)OPN->ST.clock / (double)TimerPris); +// /* SSG part priscaler set */ +// if( SSGpris ) SSGClk( OPN->ST.index, OPN->ST.clock * 2 / SSGpris ); + /* make time tables */ + init_timetables( &OPN->ST , OPN_DTTABLE , OPN_ARRATE , OPN_DRRATE ); + /* make fnumber -> increment counter table */ + for( i=0 ; i < 2048 ; i++ ) + { + /* it is freq table for octave 7 */ + /* opn freq counter = 20bit */ + OPN->FN_TABLE[i] = (UINT32)( (double)i * OPN->ST.freqbase * FREQ_RATE * (1<<7) / 2 ); + } +#if FM_LFO_SUPPORT + /* LFO freq. table */ + { + /* 3.98Hz,5.56Hz,6.02Hz,6.37Hz,6.88Hz,9.63Hz,48.1Hz,72.2Hz @ 8MHz */ +#define FM_LF(Hz) ((double)LFO_ENT*(1<LFO_FREQ[i] = (UINT32)(freq_table[i] * OPN->ST.freqbase); + } + } +#endif + +} + +/* ---------- write a OPN mode register 0x20-0x2f ---------- */ +static void OPNWriteMode(FM_OPN *OPN, int r, int v) +{ + UINT8 c; + FM_CH *CH; + + switch(r){ + case 0x21: /* Test */ + break; +#if FM_LFO_SUPPORT + case 0x22: /* LFO FREQ (YM2608/YM2612) */ + if( OPN->type & TYPE_LFOPAN ) + { + OPN->LFOIncr = (v&0x08) ? OPN->LFO_FREQ[v&7] : 0; + cur_chip = NULL; + } + break; +#endif + case 0x24: /* timer A High 8*/ + OPN->ST.TA = (OPN->ST.TA & 0x03)|(((int)v)<<2); + break; + case 0x25: /* timer A Low 2*/ + OPN->ST.TA = (OPN->ST.TA & 0x3fc)|(v&3); + break; + case 0x26: /* timer B */ + OPN->ST.TB = v; + break; + case 0x27: /* mode , timer controll */ + FMSetMode( &(OPN->ST),OPN->ST.index,v ); + break; + case 0x28: /* key on / off */ + c = v&0x03; + if( c == 3 ) break; + if( (v&0x04) && (OPN->type & TYPE_6CH) ) c+=3; + CH = OPN->P_CH; + CH = &CH[c]; + /* csm mode */ + /* if( c == 2 && (OPN->ST.mode & 0x80) ) break; */ + if(v&0x10) FM_KEYON(CH,SLOT1); else FM_KEYOFF(CH,SLOT1); + if(v&0x20) FM_KEYON(CH,SLOT2); else FM_KEYOFF(CH,SLOT2); + if(v&0x40) FM_KEYON(CH,SLOT3); else FM_KEYOFF(CH,SLOT3); + if(v&0x80) FM_KEYON(CH,SLOT4); else FM_KEYOFF(CH,SLOT4); + + break; + } +} + +/* ---------- write a OPN register (0x30-0xff) ---------- */ +static void OPNWriteReg(FM_OPN *OPN, int r, int v) +{ + UINT8 c; + FM_CH *CH; + FM_SLOT *SLOT; + + /* 0x30 - 0xff */ + if( (c = OPN_CHAN(r)) == 3 ) return; /* 0xX3,0xX7,0xXB,0xXF */ + if( (r >= 0x100) /* && (OPN->type & TYPE_6CH) */ ) c+=3; + CH = OPN->P_CH; + CH = &CH[c]; + + SLOT = &(CH->SLOT[OPN_SLOT(r)]); + switch( r & 0xf0 ) { + case 0x30: /* DET , MUL */ + set_det_mul(&OPN->ST,CH,SLOT,v); + break; + case 0x40: /* TL */ + set_tl(CH,SLOT,v,(c == 2) && (OPN->ST.mode & 0x80) ); + break; + case 0x50: /* KS, AR */ + set_ar_ksr(CH,SLOT,v,OPN->ST.AR_TABLE); + break; + case 0x60: /* DR */ + /* bit7 = AMS_ON ENABLE(YM2612) */ + set_dr(SLOT,v,OPN->ST.DR_TABLE); +#if FM_LFO_SUPPORT + if( OPN->type & TYPE_LFOPAN) + { + SLOT->amon = v>>7; + SLOT->ams = CH->ams * SLOT->amon; + } +#endif + break; + case 0x70: /* SR */ + set_sr(SLOT,v,OPN->ST.DR_TABLE); + break; + case 0x80: /* SL, RR */ + set_sl_rr(SLOT,v,OPN->ST.DR_TABLE); + break; + case 0x90: /* SSG-EG */ + SLOT->SEG = v&0x0f; + break; + case 0xa0: + switch( OPN_SLOT(r) ){ + case 0: /* 0xa0-0xa2 : FNUM1 */ + { + UINT32 fn = (((UINT32)( (CH->fn_h)&7))<<8) + v; + UINT8 blk = CH->fn_h>>3; + /* make keyscale code */ + CH->kcode = (blk<<2)|OPN_FKTABLE[(fn>>7)]; + /* make basic increment counter 32bit = 1 cycle */ + CH->fc = OPN->FN_TABLE[fn]>>(7-blk); + CH->SLOT[SLOT1].Incr=-1; + } + break; + case 1: /* 0xa4-0xa6 : FNUM2,BLK */ + CH->fn_h = v&0x3f; + break; + case 2: /* 0xa8-0xaa : 3CH FNUM1 */ + if( r < 0x100) + { + UINT32 fn = (((UINT32)(OPN->SL3.fn_h[c]&7))<<8) + v; + UINT8 blk = OPN->SL3.fn_h[c]>>3; + /* make keyscale code */ + OPN->SL3.kcode[c]= (blk<<2)|OPN_FKTABLE[(fn>>7)]; + /* make basic increment counter 32bit = 1 cycle */ + OPN->SL3.fc[c] = OPN->FN_TABLE[fn]>>(7-blk); + (OPN->P_CH)[2].SLOT[SLOT1].Incr=-1; + } + break; + case 3: /* 0xac-0xae : 3CH FNUM2,BLK */ + if( r < 0x100) + OPN->SL3.fn_h[c] = v&0x3f; + break; + } + break; + case 0xb0: + switch( OPN_SLOT(r) ){ + case 0: /* 0xb0-0xb2 : FB,ALGO */ + { + int feedback = (v>>3)&7; + CH->ALGO = v&7; + CH->FB = feedback ? 8+1 - feedback : 0; + setup_connection( CH ); + } + break; + case 1: /* 0xb4-0xb6 : L , R , AMS , PMS (YM2612/YM2608) */ + if( OPN->type & TYPE_LFOPAN) + { +#if FM_LFO_SUPPORT + /* b0-2 PMS */ + /* 0,3.4,6.7,10,14,20,40,80(cent) */ + static const double pmd_table[8]={0,3.4,6.7,10,14,20,40,80}; + static const int amd_table[4]={(int)(0/EG_STEP),(int)(1.4/EG_STEP),(int)(5.9/EG_STEP),(int)(11.8/EG_STEP) }; + CH->pms = (INT32)( (1.5/1200.0)*pmd_table[v & 7] * PMS_RATE); + /* b4-5 AMS */ + /* 0 , 1.4 , 5.9 , 11.8(dB) */ + CH->ams = amd_table[(v>>4) & 0x03]; + CH->SLOT[SLOT1].ams = CH->ams * CH->SLOT[SLOT1].amon; + CH->SLOT[SLOT2].ams = CH->ams * CH->SLOT[SLOT2].amon; + CH->SLOT[SLOT3].ams = CH->ams * CH->SLOT[SLOT3].amon; + CH->SLOT[SLOT4].ams = CH->ams * CH->SLOT[SLOT4].amon; +#endif + /* PAN */ + CH->PAN = (v>>6)&0x03; /* PAN : b6 = R , b7 = L */ + setup_connection( CH ); + + } + break; + } + break; + } +} +#endif /* BUILD_OPN */ + +#if BUILD_YM2612 +/*******************************************************************************/ +/* YM2612 local section */ +/*******************************************************************************/ +/* here's the virtual YM2612 */ +typedef struct ym2612_f { + FM_OPN OPN; /* OPN state */ + FM_CH CH[6]; /* channel state */ + int address1; /* address register1 */ + /* dac output (YM2612) */ + int dacen; + int dacout; +} YM2612; + +static int YM2612NumChips; /* total chip */ +static YM2612 *FM2612=NULL; /* array of YM2612's */ + +static int dacen; + +/* ---------- update one of chip ----------- */ +void YM2612UpdateOne(int num, INT16 **buffer, int length) +{ + YM2612 *F2612 = &(FM2612[num]); + FM_OPN *OPN = &(FM2612[num].OPN); + int i; + FM_CH *ch,*ech; + FMSAMPLE *bufL,*bufR; + int dacout = F2612->dacout; + + /* set bufer */ + bufL = buffer[0]; + bufR = buffer[1]; + + if( (void *)F2612 != cur_chip ){ + cur_chip = (void *)F2612; + + State = &OPN->ST; + cch[0] = &F2612->CH[0]; + cch[1] = &F2612->CH[1]; + cch[2] = &F2612->CH[2]; + cch[3] = &F2612->CH[3]; + cch[4] = &F2612->CH[4]; + cch[5] = &F2612->CH[5]; + /* DAC mode */ + dacen = F2612->dacen; +#if FM_LFO_SUPPORT + LFOCnt = OPN->LFOCnt; + LFOIncr = OPN->LFOIncr; + if( !LFOIncr ) lfo_amd = lfo_pmd = 0; +#endif + } + /* update frequency counter */ + OPN_CALC_FCOUNT( cch[0] ); + OPN_CALC_FCOUNT( cch[1] ); + if( (State->mode & 0xc0) ){ + /* 3SLOT MODE */ + if( cch[2]->SLOT[SLOT1].Incr==-1){ + /* 3 slot mode */ + CALC_FCSLOT(&cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] ); + CALC_FCSLOT(&cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] ); + CALC_FCSLOT(&cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] ); + CALC_FCSLOT(&cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode ); + } + }else OPN_CALC_FCOUNT( cch[2] ); + OPN_CALC_FCOUNT( cch[3] ); + OPN_CALC_FCOUNT( cch[4] ); + OPN_CALC_FCOUNT( cch[5] ); + + ech = dacen ? cch[4] : cch[5]; + /* buffering */ + for( i=0; i < length ; i++ ) + { +#if FM_LFO_SUPPORT + /* LFO */ + if( LFOIncr ) + { + lfo_amd = OPN_LFO_wave[(LFOCnt+=LFOIncr)>>LFO_SHIFT]; + lfo_pmd = lfo_amd-(LFO_RATE/2); + } +#endif + /* clear output acc. */ + out_ch[OUTD_LEFT] = out_ch[OUTD_RIGHT]= out_ch[OUTD_CENTER] = 0; + /* calcrate channel output */ + for(ch = cch[0] ; ch <= ech ; ch++) + FM_CALC_CH( ch ); + if( dacen ) *cch[5]->connect4 += dacout; + /* buffering */ + FM_BUFFERING_STEREO; + /* timer A controll */ + INTERNAL_TIMER_A( State , cch[2] ) + } + INTERNAL_TIMER_B(State,length) +#if FM_LFO_SUPPORT + OPN->LFOCnt = LFOCnt; +#endif +} + +/* -------------------------- YM2612 ---------------------------------- */ +int YM2612Init(int num, int clock, int rate, + FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler) +{ + int i; + + if (FM2612) return (-1); /* duplicate init. */ + cur_chip = NULL; /* hiro-shi!! */ + + YM2612NumChips = num; + + /* allocate extend state space */ + if( (FM2612 = (YM2612 *)emu_Malloc(sizeof(YM2612) * YM2612NumChips))==NULL) + return (-1); + /* clear */ + memset(FM2612,0,sizeof(YM2612) * YM2612NumChips); + /* allocate total level table (128kb space) */ + if( !OPNInitTable() ) + { + emu_Free( FM2612 ); + return (-1); + } + + for ( i = 0 ; i < YM2612NumChips; i++ ) { + FM2612[i].OPN.ST.index = i; + FM2612[i].OPN.type = TYPE_YM2612; + FM2612[i].OPN.P_CH = FM2612[i].CH; + FM2612[i].OPN.ST.clock = clock; + FM2612[i].OPN.ST.rate = rate; + /* FM2612[i].OPN.ST.irq = 0; */ + /* FM2612[i].OPN.ST.status = 0; */ + FM2612[i].OPN.ST.timermodel = FM_TIMER_INTERVAL; + /* Extend handler */ + FM2612[i].OPN.ST.Timer_Handler = TimerHandler; + FM2612[i].OPN.ST.IRQ_Handler = IRQHandler; + YM2612ResetChip(i); + } + return 0; +} + +/* ---------- shut down emurator ----------- */ +void YM2612Shutdown() +{ + if (!FM2612) return; + + FMCloseTable(); + emu_Free(FM2612); + FM2612 = NULL; +} + +/* ---------- reset one of chip ---------- */ +void YM2612ResetChip(int num) +{ + int i; + YM2612 *F2612 = &(FM2612[num]); + FM_OPN *OPN = &(FM2612[num].OPN); + + OPNSetPris( OPN , 12*12, 12*12, 0); + /* status clear */ + FM_IRQMASK_SET(&OPN->ST,0x03); + OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */ + + reset_channel( &OPN->ST , &F2612->CH[0] , 6 ); + + for(i = 0xb6 ; i >= 0xb4 ; i-- ) + { + OPNWriteReg(OPN,i ,0xc0); + OPNWriteReg(OPN,i|0x100,0xc0); + } + for(i = 0xb2 ; i >= 0x30 ; i-- ) + { + OPNWriteReg(OPN,i ,0); + OPNWriteReg(OPN,i|0x100,0); + } + for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(OPN,i,0); + /* DAC mode clear */ + F2612->dacen = 0; +} + +/* YM2612 write */ +/* n = number */ +/* a = address */ +/* v = value */ +int YM2612Write(int n, int a,UINT8 v) +{ + YM2612 *F2612 = &(FM2612[n]); + int addr; + + switch( a&3){ + case 0: /* address port 0 */ + F2612->OPN.ST.address = v & 0xff; + break; + case 1: /* data port 0 */ + addr = F2612->OPN.ST.address; + switch( addr & 0xf0 ) + { + case 0x20: /* 0x20-0x2f Mode */ + switch( addr ) + { + case 0x2a: /* DAC data (YM2612) */ + F2612->dacout = ((int)v - 0x80)<<(TL_BITS-7); + F2612->dacout = ((int)(v/2)-0x80)<<(TL_BITS-7); + break; + case 0x2b: /* DAC Sel (YM2612) */ + /* b7 = dac enable */ + F2612->dacen = v & 0x80; + cur_chip = NULL; + break; + default: /* OPN section */ + /* write register */ + OPNWriteMode(&(F2612->OPN),addr,v); + } + break; + default: /* 0x30-0xff OPN section */ + /* write register */ + OPNWriteReg(&(F2612->OPN),addr,v); + } + break; + case 2: /* address port 1 */ + F2612->address1 = v & 0xff; + break; + case 3: /* data port 1 */ + addr = F2612->address1; + OPNWriteReg(&(F2612->OPN),addr|0x100,v); + break; + } + return F2612->OPN.ST.irq; +} +UINT8 YM2612Read(int n,int a) +{ + YM2612 *F2612 = &(FM2612[n]); + + switch( a&3){ + case 0: /* status 0 */ + return F2612->OPN.ST.status; + case 1: + case 2: + case 3: + return F2612->OPN.ST.status; + } + return 0; +} + +int YM2612TimerOver(int n,int c) +{ + YM2612 *F2612 = &(FM2612[n]); + + if( c ) + { /* Timer B */ + TimerBOver( &(F2612->OPN.ST) ); + } + else + { /* Timer A */ + /* timer update */ + TimerAOver( &(F2612->OPN.ST) ); + /* CSM mode key,TL controll */ + if( F2612->OPN.ST.mode & 0x80 ) + { /* CSM mode total level latch and auto key on */ + CSMKeyControll( &(F2612->CH[2]) ); + } + } + return F2612->OPN.ST.irq; +} + +#endif /* BUILD_YM2612 */ diff --git a/MCUME_teensy41/teensygen/fm.h b/MCUME_teensy41/teensygen/fm.h index 8e47af0..354e038 100644 --- a/MCUME_teensy41/teensygen/fm.h +++ b/MCUME_teensy41/teensygen/fm.h @@ -1,181 +1,181 @@ - -#ifndef _H_FM_FM_ -#define _H_FM_FM_ - -#define HAS_YM2612 1 - -#define BUILD_YM2612 (HAS_YM2612 || HAS_YM3438) - -#define FM_STEREO_MIX 0 -#define FM_OUTPUT_BIT 16 -#define FM_INTERNAL_TIMER 0 - -#define FM_LFO_SUPPORT 1 -#define FM_SEG_SUPPORT 0 - -#if BUILD_YM2612 - /* in 2612intf.c */ - #define YM2612UpdateReq(chip) YM2612UpdateRequest(chip); -#endif - -/* compiler dependence */ -#ifndef OSD_CPU_H -#define OSD_CPU_H -typedef unsigned char UINT8; /* unsigned 8bit */ -typedef unsigned short UINT16; /* unsigned 16bit */ -typedef unsigned int UINT32; /* unsigned 32bit */ -typedef signed char INT8; /* signed 8bit */ -typedef signed short INT16; /* signed 16bit */ -typedef signed int INT32; /* signed 32bit */ -#endif - -#define YM2203_NUMBUF 1 -#if FM_STEREO_MIX - #define YM2151_NUMBUF 1 - #define YM2608_NUMBUF 1 - #define YM2612_NUMBUF 1 - #define YM2610_NUMBUF 1 -#else - #define YM2151_NUMBUF 2 /* FM L+R */ - #define YM2608_NUMBUF 2 /* FM L+R+ADPCM+RYTHM */ - #define YM2610_NUMBUF 2 /* FM L+R+ADPCMA+ADPCMB */ - #define YM2612_NUMBUF 2 /* FM L+R */ -#endif - -#if (FM_OUTPUT_BIT==16) -typedef INT16 FMSAMPLE; -typedef unsigned long FMSAMPLE_MIX; -#endif -#if (FM_OUTPUT_BIT==8) -typedef unsigned char FMSAMPLE; -typedef unsigned short FMSAMPLE_MIX; -#endif - -typedef void (*FM_TIMERHANDLER)(int n,int c,int cnt,double stepTime); -typedef void (*FM_IRQHANDLER)(int n,int irq); -/* FM_TIMERHANDLER : Stop or Start timer */ -/* int n = chip number */ -/* int c = Channel 0=TimerA,1=TimerB */ -/* int count = timer count (0=stop) */ -/* doube stepTime = step time of one count (sec.)*/ - -/* FM_IRQHHANDLER : IRQ level changing sense */ -/* int n = chip number */ -/* int irq = IRQ level 0=OFF,1=ON */ - -#if BUILD_YM2203 -/* -------------------- YM2203(OPN) Interface -------------------- */ - -/* -** Initialize YM2203 emulator(s). -** -** 'num' is the number of virtual YM2203's to allocate -** 'baseclock' -** 'rate' is sampling rate -** 'TimerHandler' timer callback handler when timer start and clear -** 'IRQHandler' IRQ callback handler when changed IRQ level -** return 0 = success -*/ -int YM2203Init(int num, int baseclock, int rate, - FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler); - -/* -** shutdown the YM2203 emulators .. make sure that no sound system stuff -** is touching our audio buffers ... -*/ -void YM2203Shutdown(void); - -/* -** reset all chip registers for YM2203 number 'num' -*/ -void YM2203ResetChip(int num); -/* -** update one of chip -*/ - -void YM2203UpdateOne(int num, INT16 *buffer, int length); - -/* -** Write -** return : InterruptLevel -*/ -int YM2203Write(int n,int a,unsigned char v); -/* -** Read -** return : InterruptLevel -*/ -unsigned char YM2203Read(int n,int a); - -/* -** Timer OverFlow -*/ -int YM2203TimerOver(int n, int c); - -#endif /* BUILD_YM2203 */ - -#if BUILD_YM2608 -/* -------------------- YM2608(OPNA) Interface -------------------- */ -int YM2608Init(int num, int baseclock, int rate, - void **pcmroma,int *pcmsizea,short *rhythmrom,int *rhythmpos, - FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler); -void YM2608Shutdown(void); -void YM2608ResetChip(int num); -void YM2608UpdateOne(int num, INT16 **buffer, int length); - -int YM2608Write(int n, int a,unsigned char v); -unsigned char YM2608Read(int n,int a); -int YM2608TimerOver(int n, int c ); -#endif /* BUILD_YM2608 */ - -#if (BUILD_YM2610||BUILD_YM2610B) -/* -------------------- YM2610(OPNB) Interface -------------------- */ -int YM2610Init(int num, int baseclock, int rate, - void **pcmroma,int *pcmasize,void **pcmromb,int *pcmbsize, - FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler); -void YM2610Shutdown(void); -void YM2610ResetChip(int num); -void YM2610UpdateOne(int num, INT16 **buffer, int length); -#if BUILD_YM2610B -void YM2610BUpdateOne(int num, INT16 **buffer, int length); -#endif - -int YM2610Write(int n, int a,unsigned char v); -unsigned char YM2610Read(int n,int a); -int YM2610TimerOver(int n, int c ); - -#endif /* BUILD_YM2610 */ - -#if BUILD_YM2612 -int YM2612Init(int num, int baseclock, int rate, - FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler); -void YM2612Shutdown(void); -void YM2612ResetChip(int num); -void YM2612UpdateOne(int num, INT16 **buffer, int length); -int YM2612Write(int n, int a,unsigned char v); -unsigned char YM2612Read(int n,int a); -int YM2612TimerOver(int n, int c ); - -#endif /* BUILD_YM2612 */ - -#if BUILD_YM2151 -/* -------------------- YM2151(OPM) Interface -------------------- */ -int OPMInit(int num, int baseclock, int rate, - FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler); -void OPMShutdown(void); -void OPMResetChip(int num); - -void OPMUpdateOne(int num, INT16 **buffer, int length ); -/* ---- set callback hander when port CT0/1 write ----- */ -/* CT.bit0 = CT0 , CT.bit1 = CT1 */ -/* -typedef void (*mem_write_handler)(int offset,int data); -*/ -void OPMSetPortHander(int n,mem_write_handler PortWrite); -/* JB 981119 - so it will match MAME's memory write functions scheme*/ - -int YM2151Write(int n,int a,unsigned char v); -unsigned char YM2151Read(int n,int a); -int YM2151TimerOver(int n,int c); -#endif /* BUILD_YM2151 */ - -#endif /* _H_FM_FM_ */ + +#ifndef _H_FM_FM_ +#define _H_FM_FM_ + +#define HAS_YM2612 1 + +#define BUILD_YM2612 (HAS_YM2612 || HAS_YM3438) + +#define FM_STEREO_MIX 0 +#define FM_OUTPUT_BIT 16 +#define FM_INTERNAL_TIMER 0 + +#define FM_LFO_SUPPORT 1 +#define FM_SEG_SUPPORT 0 + +#if BUILD_YM2612 + /* in 2612intf.c */ + #define YM2612UpdateReq(chip) YM2612UpdateRequest(chip); +#endif + +/* compiler dependence */ +#ifndef OSD_CPU_H +#define OSD_CPU_H +typedef unsigned char UINT8; /* unsigned 8bit */ +typedef unsigned short UINT16; /* unsigned 16bit */ +typedef unsigned int UINT32; /* unsigned 32bit */ +typedef signed char INT8; /* signed 8bit */ +typedef signed short INT16; /* signed 16bit */ +typedef signed int INT32; /* signed 32bit */ +#endif + +#define YM2203_NUMBUF 1 +#if FM_STEREO_MIX + #define YM2151_NUMBUF 1 + #define YM2608_NUMBUF 1 + #define YM2612_NUMBUF 1 + #define YM2610_NUMBUF 1 +#else + #define YM2151_NUMBUF 2 /* FM L+R */ + #define YM2608_NUMBUF 2 /* FM L+R+ADPCM+RYTHM */ + #define YM2610_NUMBUF 2 /* FM L+R+ADPCMA+ADPCMB */ + #define YM2612_NUMBUF 2 /* FM L+R */ +#endif + +#if (FM_OUTPUT_BIT==16) +typedef INT16 FMSAMPLE; +typedef unsigned long FMSAMPLE_MIX; +#endif +#if (FM_OUTPUT_BIT==8) +typedef unsigned char FMSAMPLE; +typedef unsigned short FMSAMPLE_MIX; +#endif + +typedef void (*FM_TIMERHANDLER)(int n,int c,int cnt,double stepTime); +typedef void (*FM_IRQHANDLER)(int n,int irq); +/* FM_TIMERHANDLER : Stop or Start timer */ +/* int n = chip number */ +/* int c = Channel 0=TimerA,1=TimerB */ +/* int count = timer count (0=stop) */ +/* doube stepTime = step time of one count (sec.)*/ + +/* FM_IRQHHANDLER : IRQ level changing sense */ +/* int n = chip number */ +/* int irq = IRQ level 0=OFF,1=ON */ + +#if BUILD_YM2203 +/* -------------------- YM2203(OPN) Interface -------------------- */ + +/* +** Initialize YM2203 emulator(s). +** +** 'num' is the number of virtual YM2203's to allocate +** 'baseclock' +** 'rate' is sampling rate +** 'TimerHandler' timer callback handler when timer start and clear +** 'IRQHandler' IRQ callback handler when changed IRQ level +** return 0 = success +*/ +int YM2203Init(int num, int baseclock, int rate, + FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler); + +/* +** shutdown the YM2203 emulators .. make sure that no sound system stuff +** is touching our audio buffers ... +*/ +void YM2203Shutdown(void); + +/* +** reset all chip registers for YM2203 number 'num' +*/ +void YM2203ResetChip(int num); +/* +** update one of chip +*/ + +void YM2203UpdateOne(int num, INT16 *buffer, int length); + +/* +** Write +** return : InterruptLevel +*/ +int YM2203Write(int n,int a,unsigned char v); +/* +** Read +** return : InterruptLevel +*/ +unsigned char YM2203Read(int n,int a); + +/* +** Timer OverFlow +*/ +int YM2203TimerOver(int n, int c); + +#endif /* BUILD_YM2203 */ + +#if BUILD_YM2608 +/* -------------------- YM2608(OPNA) Interface -------------------- */ +int YM2608Init(int num, int baseclock, int rate, + void **pcmroma,int *pcmsizea,short *rhythmrom,int *rhythmpos, + FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler); +void YM2608Shutdown(void); +void YM2608ResetChip(int num); +void YM2608UpdateOne(int num, INT16 **buffer, int length); + +int YM2608Write(int n, int a,unsigned char v); +unsigned char YM2608Read(int n,int a); +int YM2608TimerOver(int n, int c ); +#endif /* BUILD_YM2608 */ + +#if (BUILD_YM2610||BUILD_YM2610B) +/* -------------------- YM2610(OPNB) Interface -------------------- */ +int YM2610Init(int num, int baseclock, int rate, + void **pcmroma,int *pcmasize,void **pcmromb,int *pcmbsize, + FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler); +void YM2610Shutdown(void); +void YM2610ResetChip(int num); +void YM2610UpdateOne(int num, INT16 **buffer, int length); +#if BUILD_YM2610B +void YM2610BUpdateOne(int num, INT16 **buffer, int length); +#endif + +int YM2610Write(int n, int a,unsigned char v); +unsigned char YM2610Read(int n,int a); +int YM2610TimerOver(int n, int c ); + +#endif /* BUILD_YM2610 */ + +#if BUILD_YM2612 +int YM2612Init(int num, int baseclock, int rate, + FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler); +void YM2612Shutdown(void); +void YM2612ResetChip(int num); +void YM2612UpdateOne(int num, INT16 **buffer, int length); +int YM2612Write(int n, int a,unsigned char v); +unsigned char YM2612Read(int n,int a); +int YM2612TimerOver(int n, int c ); + +#endif /* BUILD_YM2612 */ + +#if BUILD_YM2151 +/* -------------------- YM2151(OPM) Interface -------------------- */ +int OPMInit(int num, int baseclock, int rate, + FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler); +void OPMShutdown(void); +void OPMResetChip(int num); + +void OPMUpdateOne(int num, INT16 **buffer, int length ); +/* ---- set callback hander when port CT0/1 write ----- */ +/* CT.bit0 = CT0 , CT.bit1 = CT1 */ +/* +typedef void (*mem_write_handler)(int offset,int data); +*/ +void OPMSetPortHander(int n,mem_write_handler PortWrite); +/* JB 981119 - so it will match MAME's memory write functions scheme*/ + +int YM2151Write(int n,int a,unsigned char v); +unsigned char YM2151Read(int n,int a); +int YM2151TimerOver(int n,int c); +#endif /* BUILD_YM2151 */ + +#endif /* _H_FM_FM_ */ diff --git a/MCUME_teensy41/teensygen/platform_config.h b/MCUME_teensy41/teensygen/platform_config.h index 3464dc2..1791885 100644 --- a/MCUME_teensy41/teensygen/platform_config.h +++ b/MCUME_teensy41/teensygen/platform_config.h @@ -4,13 +4,13 @@ #define TEECOMPUTER 1 #ifdef TEECOMPUTER -//#define ILI9341 1 -//#define ST7789 1 -//#define TFTSPI1 1 -#define HAS_T4_VGA 1 -#define HAS_SND 1 +#define TFTSPI1 1 +//#define HAS_T4_VGA 1 +//#define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 -//#define INVX 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 #define PT8211 1 #else @@ -18,8 +18,12 @@ #define HAS_T4_VGA 1 //#define INVX 1 #define INVY 1 -#define HAS_SND 1 +//#define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 +#define PT8211 1 #endif diff --git a/MCUME_teensy41/teensygen/render.c b/MCUME_teensy41/teensygen/render.c index 5885e63..fed45b7 100644 --- a/MCUME_teensy41/teensygen/render.c +++ b/MCUME_teensy41/teensygen/render.c @@ -9,9 +9,6 @@ #include "shared.h" #include "platform_config.h" -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#endif extern void emu_DrawLine16(unsigned short *src, int width , int height, int line); extern void emu_printf(char * text); diff --git a/MCUME_teensy41/teensygen/shared.h b/MCUME_teensy41/teensygen/shared.h index 5120897..55bb29e 100644 --- a/MCUME_teensy41/teensygen/shared.h +++ b/MCUME_teensy41/teensygen/shared.h @@ -4,7 +4,6 @@ #define LSB_FIRST 1 -#define SOUND_PRESENT 1 //#define ALIGN_LONG 1 #define GENESIS_HACKS 1 diff --git a/MCUME_teensy41/teensygen/sound.c b/MCUME_teensy41/teensygen/sound.c index 85f20e7..88013fb 100644 --- a/MCUME_teensy41/teensygen/sound.c +++ b/MCUME_teensy41/teensygen/sound.c @@ -1,170 +1,169 @@ -/* - sound.c - YM2612 and SN76489 emulation -*/ - -#include "shared.h" - -/* YM2612 data */ -int fm_timera_tab[0x400]; /* Precalculated timer A values */ -int fm_timerb_tab[0x100]; /* Precalculated timer B values */ -uint8 fm_reg[2][0x100]; /* Register arrays (2x256) */ -uint8 fm_latch[2]; /* Register latches */ -uint8 fm_status; /* Read-only status flags */ -t_timer timer[2]; /* Timers A and B */ - -/* Initialize the YM2612 and SN76489 emulation */ -void sound_init(void) -{ - /* Timers run at half the YM2612 input clock */ - float clock = ((53.693175 / 7) / 2); - int i; - - /* Make Timer A table */ - for(i = 0; i < 1024; i += 1) - { - /* Formula is "time(us) = 72 * (1024 - A) / clock" */ - fm_timera_tab[i] = ((int)(float)(72 * (1024 - i)) / (clock)); - } - - /* Make Timer B table */ - for(i = 0; i < 256; i += 1) - { - /* Formula is "time(us) = 1152 * (256 - B) / clock" */ - fm_timerb_tab[i] = (int)(float)(1152 * (256 - i)) / clock; - } -} - -void sound_reset(void) -{ - if(snd.enabled) - { - YM2612ResetChip(0); - } -} - -void fm_write(int address, int data) -{ - int a0 = (address & 1); - int a1 = (address >> 1) & 1; - - if(a0) - { - /* Register data */ - fm_reg[a1][fm_latch[a1]] = data; - - /* Timer control only in set A */ - if(a1 == 0) - switch(fm_latch[a1]) - { - case 0x24: /* Timer A (LSB) */ - timer[0].index = (timer[0].index & 0x0003) | (data << 2); - timer[0].index &= 0x03FF; - timer[0].base = fm_timera_tab[timer[0].index]; - break; - - case 0x25: /* Timer A (MSB) */ - timer[0].index = (timer[0].index & 0x03FC) | (data & 3); - timer[0].index &= 0x03FF; - timer[0].base = fm_timera_tab[timer[0].index]; - break; - - case 0x26: /* Timer B */ - timer[1].index = data; - timer[1].base = timer[1].count = fm_timerb_tab[timer[1].index]; - break; - - case 0x27: /* Timer Control */ - - /* LOAD */ - timer[0].running = (data >> 0) & 1; - if(timer[0].running) timer[0].count = 0; - timer[1].running = (data >> 1) & 1; - if(timer[1].running) timer[1].count = 0; - - /* ENABLE */ - timer[0].enable = (data >> 2) & 1; - timer[1].enable = (data >> 3) & 1; - - /* RESET */ - if(data & 0x10) fm_status &= ~1; - if(data & 0x20) fm_status &= ~2; - break; - } - } - else - { - /* Register latch */ - fm_latch[a1] = data; - } - - if(snd.enabled) - { - if(snd.fm.curStage - snd.fm.lastStage > 1) - { - int16 *tempBuffer[2]; - tempBuffer[0] = snd.fm.buffer[0] + snd.fm.lastStage; - tempBuffer[1] = snd.fm.buffer[1] + snd.fm.lastStage; - YM2612UpdateOne(0, (int16 **)tempBuffer, snd.fm.curStage - snd.fm.lastStage); - snd.fm.lastStage = snd.fm.curStage; - } - - YM2612Write(0, address & 3, data); - } -} - - -int fm_read(int address) -{ - return (fm_status); -} - - -void fm_update_timers(void) -{ - int i; - - /* Process YM2612 timers */ - for(i = 0; i < 2; i += 1) - { - /* Is the timer running? */ - if(timer[i].running) - { - /* Each scanline takes up roughly 64 microseconds */ - timer[i].count += 64; - - /* Check if the counter overflowed */ - if(timer[i].count > timer[i].base) - { - /* Reload counter */ - timer[i].count = 0; - - /* Disable timer */ - timer[i].running = 0; - - /* Set overflow flag (if flag setting is enabled) */ - if(timer[i].enable) - { - fm_status |= (1 << i); - } - } - } - } -} - -void psg_write(int data) -{ - if(snd.enabled) - { - if(snd.psg.curStage - snd.psg.lastStage > 1) - { - int16 *tempBuffer; - tempBuffer = snd.psg.buffer + snd.psg.lastStage; - SN76496Update(0, tempBuffer, snd.psg.curStage - snd.psg.lastStage); - snd.psg.lastStage = snd.psg.curStage; - } - - SN76496Write(0, data); - } -} - +/* + sound.c + YM2612 and SN76489 emulation +*/ + +#include "shared.h" + +/* YM2612 data */ +int fm_timera_tab[0x400]; /* Precalculated timer A values */ +int fm_timerb_tab[0x100]; /* Precalculated timer B values */ +uint8 fm_reg[2][0x100]; /* Register arrays (2x256) */ +uint8 fm_latch[2]; /* Register latches */ +uint8 fm_status; /* Read-only status flags */ +t_timer timer[2]; /* Timers A and B */ + +/* Initialize the YM2612 and SN76489 emulation */ +void sound_init(void) +{ + /* Timers run at half the YM2612 input clock */ + float clock = ((53.693175 / 7) / 2); + int i; + + /* Make Timer A table */ + for(i = 0; i < 1024; i += 1) + { + /* Formula is "time(us) = 72 * (1024 - A) / clock" */ + fm_timera_tab[i] = ((int)(float)(72 * (1024 - i)) / (clock)); + } + + /* Make Timer B table */ + for(i = 0; i < 256; i += 1) + { + /* Formula is "time(us) = 1152 * (256 - B) / clock" */ + fm_timerb_tab[i] = (int)(float)(1152 * (256 - i)) / clock; + } +} + +void sound_reset(void) +{ + if(snd.enabled) + { + YM2612ResetChip(0); + } +} + +void fm_write(int address, int data) +{ + int a0 = (address & 1); + int a1 = (address >> 1) & 1; + + if(a0) + { + /* Register data */ + fm_reg[a1][fm_latch[a1]] = data; + + /* Timer control only in set A */ + if(a1 == 0) + switch(fm_latch[a1]) + { + case 0x24: /* Timer A (LSB) */ + timer[0].index = (timer[0].index & 0x0003) | (data << 2); + timer[0].index &= 0x03FF; + timer[0].base = fm_timera_tab[timer[0].index]; + break; + + case 0x25: /* Timer A (MSB) */ + timer[0].index = (timer[0].index & 0x03FC) | (data & 3); + timer[0].index &= 0x03FF; + timer[0].base = fm_timera_tab[timer[0].index]; + break; + + case 0x26: /* Timer B */ + timer[1].index = data; + timer[1].base = timer[1].count = fm_timerb_tab[timer[1].index]; + break; + + case 0x27: /* Timer Control */ + + /* LOAD */ + timer[0].running = (data >> 0) & 1; + if(timer[0].running) timer[0].count = 0; + timer[1].running = (data >> 1) & 1; + if(timer[1].running) timer[1].count = 0; + + /* ENABLE */ + timer[0].enable = (data >> 2) & 1; + timer[1].enable = (data >> 3) & 1; + + /* RESET */ + if(data & 0x10) fm_status &= ~1; + if(data & 0x20) fm_status &= ~2; + break; + } + } + else + { + /* Register latch */ + fm_latch[a1] = data; + } + + if(snd.enabled) + { + if(snd.fm.curStage - snd.fm.lastStage > 1) + { + int16 *tempBuffer[2]; + tempBuffer[0] = snd.fm.buffer[0] + snd.fm.lastStage; + tempBuffer[1] = snd.fm.buffer[1] + snd.fm.lastStage; + YM2612UpdateOne(0, *(int16 **)tempBuffer, snd.fm.curStage - snd.fm.lastStage); + snd.fm.lastStage = snd.fm.curStage; + } + + YM2612Write(0, address & 3, data); + } +} + + +int fm_read(int address) +{ + return (fm_status); +} + + +void fm_update_timers(void) +{ + int i; + + /* Process YM2612 timers */ + for(i = 0; i < 2; i += 1) + { + /* Is the timer running? */ + if(timer[i].running) + { + /* Each scanline takes up roughly 64 microseconds */ + timer[i].count += 64; + + /* Check if the counter overflowed */ + if(timer[i].count > timer[i].base) + { + /* Reload counter */ + timer[i].count = 0; + + /* Disable timer */ + timer[i].running = 0; + + /* Set overflow flag (if flag setting is enabled) */ + if(timer[i].enable) + { + fm_status |= (1 << i); + } + } + } + } +} + +void psg_write(int data) +{ + if(snd.enabled) + { + if(snd.psg.curStage - snd.psg.lastStage > 1) + { + int16 *tempBuffer; + tempBuffer = snd.psg.buffer + snd.psg.lastStage; + SN76496Update(0, tempBuffer, snd.psg.curStage - snd.psg.lastStage); + snd.psg.lastStage = snd.psg.curStage; + } + + SN76496Write(0, data); + } +} diff --git a/MCUME_teensy41/teensygen/system.c b/MCUME_teensy41/teensygen/system.c index e6f18a2..15d4039 100644 --- a/MCUME_teensy41/teensygen/system.c +++ b/MCUME_teensy41/teensygen/system.c @@ -23,9 +23,15 @@ t_input input; t_snd snd; static int sound_tbl[262]; -#define SND_SIZE (snd.buffer_size * sizeof(int16)) +#define SND_SIZE (snd.buffer_size * sizeof(int16)) +#define MAX_SND_SIZE 1024 + +static int16 * fm_buffer1[MAX_SND_SIZE]; +static int16 * fm_buffer2[MAX_SND_SIZE]; +static int16 * psg_buffer[MAX_SND_SIZE]; + int audio_init(int rate) { int i; @@ -49,16 +55,21 @@ int audio_init(int rate) snd.buffer_size = (rate / 60); snd.sample_rate = rate; + snd.fm.buffer[0] = &fm_buffer1[0]; + snd.fm.buffer[1] = &fm_buffer2[0]; + snd.psg.buffer = &psg_buffer[0]; + + /* Allocate sound buffers */ - snd.fm.buffer[0] = emu_Malloc(SND_SIZE); - snd.fm.buffer[1] = emu_Malloc(SND_SIZE); - snd.psg.buffer = emu_Malloc(SND_SIZE); + //snd.fm.buffer[0] = emu_Malloc(SND_SIZE); + //snd.fm.buffer[1] = emu_Malloc(SND_SIZE); + //snd.psg.buffer = emu_Malloc(SND_SIZE); /* Make sure we could allocate everything */ - if(!snd.fm.buffer[0] || !snd.fm.buffer[1] || !snd.psg.buffer) - { - return (0); - } + //if(!snd.fm.buffer[0] || !snd.fm.buffer[1] || !snd.psg.buffer) + //{ + // return (0); + //} /* Initialize sound chip emulation */ SN76496_sh_start(zclk, 100, rate); @@ -96,9 +107,13 @@ void system_reset(void) YM2612ResetChip(0); //memset(snd.buffer[0], 0, SND_SIZE); //memset(snd.buffer[1], 0, SND_SIZE); - memset(snd.fm.buffer[0], 0, SND_SIZE); - memset(snd.fm.buffer[1], 0, SND_SIZE); - memset(snd.psg.buffer, 0, SND_SIZE); + // memset(snd.fm.buffer[0], 0, SND_SIZE); + // memset(snd.fm.buffer[1], 0, SND_SIZE); + // memset(snd.psg.buffer, 0, SND_SIZE); + + memset(&fm_buffer1[0], 0, MAX_SND_SIZE); + memset(&fm_buffer2[0], 0, MAX_SND_SIZE); + memset(&psg_buffer[0], 0, MAX_SND_SIZE); } } @@ -228,15 +243,26 @@ void audio_play_sample(int16 *bufl, int16 *bufr, int length) length = length/2; + snd.fm.buffer[0] = &fm_buffer1[0]; + snd.fm.buffer[1] = &fm_buffer2[0]; + snd.psg.buffer = &psg_buffer[0]; + + int16 *tempBuffer[2]; tempBuffer[0] = snd.fm.buffer[0]; tempBuffer[1] = snd.fm.buffer[1]; - YM2612UpdateOne(0, (int16 **)tempBuffer, length); + //return; - tempBuffer[0] = snd.psg.buffer; - SN76496Update(0, tempBuffer[0], length); + //YM2612UpdateOne(0, (int16 **)tempBuffer, length); + //tempBuffer[0] = snd.psg.buffer; + //SN76496Update(0, tempBuffer[0], length); + + //SN76496Update(0, &psg_buffer[0], length); + + + for(i = 0; i < length /*snd.buffer_size*/; i += 1) { int16 psg = snd.psg.buffer[i] / 2; diff --git a/MCUME_teensy41/teensygen/t4_dsp.cpp b/MCUME_teensy41/teensygen/t4_dsp.cpp new file mode 100644 index 0000000..43301fa --- /dev/null +++ b/MCUME_teensy41/teensygen/t4_dsp.cpp @@ -0,0 +1,1774 @@ +/* + TFT/VGA driver + DMA TFT driver based on C64 ILI9341 dma driver from Frank Bösing, 2017 +*/ + +#include "T4_DSP.h" + +#include +#include + +#include "font8x8.h" + +// TFT constants and variables +#define TFT_LINEARINT 1 +#define LINEARINT_HACK 1 +#define DMA_LINES_PER_BLOCK 64 +#define DMA_NUM_SETTINGS 4 + +#define TFT_SWRESET 0x01 +#define TFT_SLPOUT 0x11 +#define TFT_INVON 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_MADCTL 0x36 +#define TFT_PIXFMT 0x3A +#define TFT_MADCTL_MY 0x80 +#define TFT_MADCTL_MX 0x40 +#define TFT_MADCTL_MV 0x20 +#define TFT_MADCTL_ML 0x10 +#define TFT_MADCTL_RGB 0x00 +#define TFT_MADCTL_BGR 0x08 +#define TFT_MADCTL_MH 0x04 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) +//#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) +//#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) +//#define R16(rgb) ((rgb>>8)&0xf8) +//#define G16(rgb) ((rgb>>3)&0xfc) +//#define B16(rgb) ((rgb<<3)&0xf8) + +// LPSPI4 = SPI0 in Teensy 4.0 +// LPSPI3 = SPI1 in Teensy 4.0 +// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) + +#ifdef TFTSPI1 +#define SPI SPI1 +#define LPSPIP_TDR LPSPI3_TDR +#define LPSPIP_CR LPSPI3_CR +#define LPSPIP_CFGR1 LPSPI3_CFGR1 +#define LPSPIP_TCR LPSPI3_TCR +#define LPSPIP_DER LPSPI3_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX +#else +#define LPSPIP_TDR LPSPI4_TDR +#define LPSPIP_CR LPSPI4_CR +#define LPSPIP_CFGR1 LPSPI4_CFGR1 +#define LPSPIP_TCR LPSPI4_TCR +#define LPSPIP_DER LPSPI4_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX +#endif + +#define SPICLOCK 60000000 +#define SPI_MODE SPI_MODE0 + +// VGA constants and macros +typedef uint8_t vga_pixel; +#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) + +static DMASetting dmasettings[DMA_NUM_SETTINGS]; +static DMAChannel dmatx; +static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K +static volatile uint8_t rstop = 0; +static volatile bool cancelled = false; +static volatile uint8_t curTransfer = 0; +static uint8_t nbTransfer = 0; +static uint16_t * tft_buffer; +static int tft_width; +static int tft_height; +static int tft_stride; + +#define DELAY_MASK 0x80 +PROGMEM static const uint8_t init_commands[] = { + 1+DELAY_MASK, TFT_SWRESET, 150, + 1+DELAY_MASK, TFT_SLPOUT, 255, + 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, + 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, + 1, TFT_INVON, + 1, TFT_DISPON, + 0 +}; + +// VGA constants and variables +// Objective: +// generates VGA signal fully in hardware with as little as possible CPU help + +// Principle: +// QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) +// 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate +// RGB out, combined to create 8bits(/12bits) output. + +// Note: +// - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels +// - experimental resolution: 352x240,352x480 +// - experimental resolution: 512x240,512x480 (not stable) +// - video memory is allocated using malloc in T4 heap +// - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing +// but tried to be compensated by pixel shifting +// - Default is 8bits RRRGGGBB (332) +// But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! +// - Only ok at 600MHz else some disturbances visible + + + +#define TOP_BORDER 40 +#define PIN_HBLANK 15 + +#define PIN_R_B2 33 +#define PIN_R_B1 4 +#define PIN_R_B0 3 +#define PIN_G_B2 2 +#define PIN_G_B1 13 +#define PIN_G_B0 11 +#define PIN_B_B1 12 +#define PIN_B_B0 10 + + +#define DMA_HACK 0x80 + +#define R16(rgb) ((rgb>>8)&0xf8) +#define G16(rgb) ((rgb>>3)&0xfc) +#define B16(rgb) ((rgb<<3)&0xf8) + +// VGA 640x480@60Hz +// Screen refresh rate 60 Hz +// Vertical refresh 31.46875 kHz +// Pixel freq. 25.175 MHz +// +// Visible area 640 25.422045680238 us +// Front porch 16 0.63555114200596 us +// Sync pulse 96 3.8133068520357 us +// Back porch 48 1.9066534260179 us +// Whole line 800 31.777557100298 us + +#define frame_freq 60.0 // Hz +#define line_freq 31.46875 // KHz +#define pix_freq (line_freq*800) // KHz (25.175 MHz) + +// pix_period = 39.7ns +// H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) +#define frontporch_pix 20 //16 +#define backporch_pix 44 //48 + +// Flexio Clock +// PLL3 SW CLOCK (3) => 480 MHz +// PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) +#define FLEXIO_CLK_SEL_PLL3 3 +#define FLEXIO_CLK_SEL_PLL5 2 + +/* Set video PLL */ +// There are /1, /2, /4, /8, /16 post dividers for the Video PLL. +// The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, +// and CCM_ANALOG_MISC2 register sets according to the following equation. +// PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + +// nfact: +// This field controls the PLL loop divider. +// Valid range for DIV_SELECT divider value: 27~54. + +#define POST_DIV_SELECT 2 + +// Full buffer including back/front porch +static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; +static uint32_t dstbuffer __attribute__((aligned(32))); + +// Visible vuffer +static vga_pixel * vga_buffer; +static int vga_width; +static int vga_height; +static int vga_stride; + +static int maxpixperline; +static int left_border; +static int right_border; +static int line_double; +static int pix_shift; +static int ref_div_select; +static int ref_freq_num; +static int ref_freq_denom; +static int ref_pix_shift; +static int combine_shiftreg; + +#ifdef DEBUG +static uint32_t ISRTicks_prev = 0; +volatile uint32_t ISRTicks = 0; +#endif + +uint8_t T4_DSP::_rst; +uint8_t T4_DSP::_cs; +uint8_t T4_DSP::_dc; +uint8_t T4_DSP::_mosi; +uint8_t T4_DSP::_sclk; +uint8_t T4_DSP::_vsync_pin = -1; +DMAChannel T4_DSP::flexio1DMA; +DMAChannel T4_DSP::flexio2DMA; + +static volatile uint32_t VSYNC = 0; +static volatile uint32_t currentLine=0; +#define NOP asm volatile("nop\n\t"); +static gfx_mode_t gfxmode = MODE_UNDEFINED; + + +FASTRUN void T4_DSP::TFT_isr(void) { + dmatx.clearInterrupt(); + curTransfer++; + if (curTransfer >= nbTransfer) { + curTransfer = 0; + if (cancelled) { + dmatx.disable(); + rstop = 1; + } + } + arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); +} + +FASTRUN void T4_DSP::QT3_isr(void) { + TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); + TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); + + cli(); + + // V-PULSE + if (currentLine > 0) { + digitalWrite(_vsync_pin, 1); + VSYNC = 0; + } else { + digitalWrite(_vsync_pin, 0); + VSYNC = 1; + } + + currentLine++; + currentLine = currentLine % 525; + + + uint32_t y = (currentLine - TOP_BORDER) >> line_double; + // Visible area + + if (y >= 0 && y < vga_height) { + // Disable DMAs + //DMA_CERQ = flexio2DMA.channel; + //DMA_CERQ = flexio1DMA.channel; + + // Setup source adress + // Aligned 32 bits copy + unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; + flexio2DMA.TCD->SADDR = p; + if (pix_shift & DMA_HACK) + { + // Unaligned copy + uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; + flexio1DMA.TCD->SADDR = p2; + } + else { + p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 + flexio1DMA.TCD->SADDR = p; + } + + // Enable DMAs + //flexio2DMA.enable(); + //flexio1DMA.enable(); + DMA_SERQ = flexio2DMA.channel; + DMA_SERQ = flexio1DMA.channel; + arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); + } + sei(); + +#ifdef DEBUG + ISRTicks++; +#endif + asm volatile("dsb"); +} + +static void setDmaStruct() { + uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; + uint16_t * fb = (uint16_t*)malloc(remaining); + tft_buffer = fb; + tft_width = TFT_WIDTH; + tft_height = TFT_HEIGHT; + tft_stride = TFT_WIDTH; + uint16_t col=RGBVAL16(0x00,0x00,0x00); + int i=0; + while (remaining > 0) { + int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); + blocks[i] = fb; + for (int j=0;jATTR_DST = 1; + dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); + dmasettings[i].interruptAtCompletion(); + fb += len/2; + remaining -= len; + i++; + } + dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); + nbTransfer = i; +} + +static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 +{ +//if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; + CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE + | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 + | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); + CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; + CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock + const int div_post_pll = 1; // other values: 2,4 + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass +} + +T4_DSP::T4_DSP() +{ + _cs = TFT_CS; + _dc = TFT_DC; + _rst = TFT_RST; + _mosi = TFT_MOSI; + _sclk = TFT_SCLK; + pinMode(_dc, OUTPUT); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, 1); + digitalWrite(_dc, 1); + _vsync_pin = 8; +} + + +void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { + int dx=0; + int dy=0; + digitalWrite(_dc, 0); + SPI.transfer(TFT_CASET); + digitalWrite(_dc, 1); + SPI.transfer16(x1+dx); + digitalWrite(_dc, 1); + SPI.transfer16(x2+dx); + digitalWrite(_dc, 0); + SPI.transfer(TFT_PASET); + digitalWrite(_dc, 1); + SPI.transfer16(y1+dy); + digitalWrite(_dc, 1); + SPI.transfer16(y2+dy); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + return; +} + +void T4_DSP::tft_setup(bool isST) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + // RESET if reset pin defined + if (_rst != 0xff) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + const uint8_t *addr = init_commands; + uint8_t count; + digitalWrite(_cs, 0); + while (count = *addr++) { + uint8_t command = *addr++; + if ( (command == TFT_INVON) && (!isST) ) { + // Skip TFT_INVON for ILI + } + else { + digitalWrite(_dc, 0); // command + SPI.transfer(command); + uint16_t ms = count & DELAY_MASK; + count &= ~DELAY_MASK; + while (--count > 0) { // data + uint8_t data = *addr++; + if ( (command == TFT_MADCTL) && (isST) ) { + data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; + } + digitalWrite(_dc, 1); + SPI.transfer(data); + } + if (ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + digitalWrite(_cs, 1); + SPI.endTransaction(); + delay(2); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + } + } + } + digitalWrite(_cs, 1); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + SPI.endTransaction(); + /* + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_dc, 0); + digitalWrite(_cs, 0); + SPI.transfer(TFT_MADCTL); + digitalWrite(_dc, 1); + SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); + // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); + digitalWrite(_cs, 1); + SPI.endTransaction(); + */ + cancelled = false; +} + +// display VGA image +gfx_error_t T4_DSP::begin(gfx_mode_t mode) +{ + uint32_t flexio_clock_div; + combine_shiftreg = 0; +// int div_select = 49; +// int num = 135; +// int denom = 100; + int div_select = 20; + int num = 9800; + int denom = 10000; + int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; + int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; + set_videoClock(div_select,num,denom,true); + +#ifdef DEBUG + Serial.println(mode); + Serial.println("mode"); +#endif + + switch(mode) + { + case MODE_TFTILI_320x240: +#ifdef DEBUG + Serial.println("TFTILI_320x240"); +#endif + tft_setup(false); + gfxmode = mode; + break; + case MODE_TFTST_320x240: +#ifdef DEBUG + Serial.println("TFTST_320x240"); +#endif + tft_setup(true); + gfxmode = mode; + break; + + case MODE_VGA_320x240: +#ifdef DEBUG + Serial.println("VGA_320x240"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_320x480: +#ifdef DEBUG + Serial.println("VGA_320x480"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_640x240: +#ifdef DEBUG + Serial.println("VGA_640x240"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/pix_freq; + line_double = 1; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_640x480: +#ifdef DEBUG + Serial.println("VGA_640x480"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = (flexio_freq/pix_freq); + line_double = 0; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_512x240: +#ifdef DEBUG + Serial.println("VGA_512x240"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 1; + pix_shift = 0; + break; + + case MODE_VGA_512x480: +#ifdef DEBUG + Serial.println("VGA_512x480"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 0; + pix_shift = 0; + break; + + case MODE_VGA_352x240: +#ifdef DEBUG + Serial.println("VGA_352x240"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_352x480: +#ifdef DEBUG + Serial.println("VGA_352x480"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + } + + if (mode >= MODE_VGA_320x240) + { + if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { + fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); + digitalWrite(_cs, 0); + digitalWrite(_dc, 0); + SPI.transfer(TFT_DISPOFF); + digitalWrite(_cs, 1); + delay(20); + digitalWrite(_cs, 0); + digitalWrite(_cs, 1); + } + gfxmode = mode; + + maxpixperline = vga_stride; + // Save param for tweek adjustment + ref_div_select = div_select; + ref_freq_num = num; + ref_freq_denom = denom; + ref_pix_shift = pix_shift; + +#ifdef DEBUG + Serial.println("frequency"); + Serial.println(flexio_freq); + Serial.println("div"); + Serial.println(flexio_freq/pix_freq); +#endif + + pinMode(_vsync_pin, OUTPUT); + pinMode(PIN_HBLANK, OUTPUT); + + /* Basic pin setup FlexIO1 */ + pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 + pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 + pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 + pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 + /* Basic pin setup FlexIO2 */ + pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 + pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 + pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 + pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 + + /* High speed and drive strength configuration */ + *(portControlRegister(PIN_G_B2)) = 0xFF; + *(portControlRegister(PIN_R_B0)) = 0xFF; + *(portControlRegister(PIN_R_B1)) = 0xFF; + *(portControlRegister(PIN_R_B2)) = 0xFF; + *(portControlRegister(PIN_B_B0)) = 0xFF; + *(portControlRegister(PIN_B_B1)) = 0xFF; + *(portControlRegister(PIN_G_B0)) = 0xFF; + *(portControlRegister(PIN_G_B1)) = 0xFF; + + /* Set clock for FlexIO1 and FlexIO2 */ + CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) + | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); + CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) + | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); + + + /* Set up pin mux FlexIO1 */ + *(portConfigRegister(PIN_G_B2)) = 0x14; + *(portConfigRegister(PIN_R_B0)) = 0x14; + *(portConfigRegister(PIN_R_B1)) = 0x14; + *(portConfigRegister(PIN_R_B2)) = 0x14; + /* Set up pin mux FlexIO2 */ + *(portConfigRegister(PIN_B_B0)) = 0x14; + *(portConfigRegister(PIN_B_B1)) = 0x14; + *(portConfigRegister(PIN_G_B0)) = 0x14; + *(portConfigRegister(PIN_G_B1)) = 0x14; + + /* Enable the clock */ + CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + /* Enable the FlexIO with fast access */ + FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + + uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; + uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; + + /* Shifter 0 registers for FlexIO2 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 + inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter + stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled + startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable + timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 + timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock + pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output + pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity + shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode + /* Shifter 0 registers for FlexIO1 */ + FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + /* Shifter 0 registers for FlexIO1 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 + FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + if (combine_shiftreg) { + pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled + FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + } + /* Timer 0 registers for FlexIO2 */ + timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset + timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output + timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset + timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare + timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert + stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled + startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled + if (combine_shiftreg) { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag + } + else { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag + } + triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low + triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected + pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled + //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 + //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high + timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode + // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) + + int shifts_per_transfer; + if (combine_shiftreg) { + shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 + } + else { + shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 + } + FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); + /* Timer 0 registers for FlexIO1 */ + FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); +#ifdef DEBUG + Serial.println("FlexIO setup complete"); +#endif + + /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ + if (combine_shiftreg) { + FLEXIO2_SHIFTSDEN |= (1<<1); + FLEXIO1_SHIFTSDEN |= (1<<1); + } + else { + FLEXIO2_SHIFTSDEN |= (1<<0); + FLEXIO1_SHIFTSDEN |= (1<<0); + } + /* Disable DMA channel so it doesn't start transferring yet */ + flexio1DMA.disable(); + flexio2DMA.disable(); + /* Set up DMA channel to use Shifter 0 trigger */ + flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); + flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); + + + if (combine_shiftreg) { + flexio2DMA.TCD->NBYTES = 8; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 8; + flexio2DMA.TCD->CITER = maxpixperline / 8; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + flexio1DMA.TCD->NBYTES = 8; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 8; + flexio1DMA.TCD->CITER = maxpixperline / 8; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Setup DMA2 Flexio2 copy + flexio2DMA.TCD->NBYTES = 4; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 4; + flexio2DMA.TCD->CITER = maxpixperline / 4; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + // Setup DMA1 Flexio1 copy + // Use pixel shift to avoid color smearing? + if (pix_shift & DMA_HACK) + { + if (pix_shift & 0x3 == 0) { + // Aligned 32 bits copy (32bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Unaligned (source) 32 bits copy (8bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 1; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion + } + } + else + { + // Aligned 32 bits copy + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + } + +#ifdef DEBUG + Serial.println("DMA setup complete"); +#endif + + // enable clocks for QTIMER3: generates the 15KHz for hsync + // Pulse: + // low : 3.8133 us => 569x6.7ns + // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) + // (OLD TEST) + // (4us low, 28us high => 32us) + // (597x6.7ns for 4us) + // (4179x6.7ns for 28us) + CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 + //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 + + #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz + #define MARGIN_D 1000 + + TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer + // Invert output pin as we want the interupt on rising edge + TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) + TMR3_CNTR3 = 0; + TMR3_LOAD3 = 0; + + /* Inverted timings */ + unsigned long long cpu_freq = F_CPU; + unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; + int rate2 = rate; + + int substract = 1; + if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { + substract=5; + rate2=1652; + } + + #ifdef DEBUG + Serial.print("MARGIN_N is: "); + Serial.println(rate2, DEC); + Serial.print("SUBSTRACT is: "); + Serial.println(substract, DEC); +#endif + TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; + TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; + /* + TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; + */ + TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on + TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), + // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) + //configure Teensy pin Compare output + IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 + attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function + NVIC_ENABLE_IRQ(IRQ_QTIMER3); +#ifdef DEBUG + Serial.println("QTIMER3 setup complete"); + Serial.print("V-PIN is "); + Serial.println(_vsync_pin); +#endif + + /* initialize gfx buffer */ + if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift + if (gfxbuffer == NULL) return(GFX_ERROR); +#ifdef DEBUG + Serial.println("Memory allocated"); +#endif + + memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); + vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; +#ifdef DEBUG + Serial.println(vga_stride); + Serial.println(vga_height); + Serial.println("Screen cleared"); +#endif + } + + return(GFX_OK); +} + +gfx_mode_t T4_DSP::getMode(void) +{ + return gfxmode; +} + +void T4_DSP::startRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + curTransfer = 0; + rstop = 0; + //dmatx.begin(true); + dmatx.attachInterrupt(TFT_isr); + setDmaStruct(); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + + digitalWrite(_cs, HIGH); + SPI.begin(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + + LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: + LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX + LPSPIP_TCR = 15; // Framesize 16 Bits + //LPSPIP_FCR = 0; // Fifo Watermark + LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable + LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: + dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); + + dmatx = dmasettings[0]; + digitalWrite(_cs, 0); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + dmatx.enable(); + } +} + + +void T4_DSP::stopRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + rstop = 1; + unsigned long m = millis(); + cancelled = true; + while (!rstop) { + if ((millis() - m) > 100) break; + delay(10); + asm volatile("wfi"); + }; + rstop = 0; + delay(50); + cancelled = false; + dmatx.detachInterrupt(); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + SPI.end(); +#ifdef ST7789 +// begin(gfxmode); +#endif + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + } +} + +int T4_DSP::get_frame_buffer_size(int *width, int *height) { + if (gfxmode < MODE_VGA_320x240) { + if (width != nullptr) *width = tft_width; + if (height != nullptr) *height = tft_height; + return tft_stride; + } + else { + if (width != nullptr) *width = vga_width; + if (height != nullptr) *height = vga_height; + return vga_stride; + } +} + +void T4_DSP::waitSync() +{ + if (gfxmode >= MODE_VGA_320x240) { + while (VSYNC == 0) {}; + } +} + +void T4_DSP::waitLine(int line) +{ + if (gfxmode >= MODE_VGA_320x240) { + while (currentLine != line) {}; + } +} + +/*********************************************************************************************** + No DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreenNoDma(uint16_t color) { + if (gfxmode < MODE_VGA_320x240) { + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + int i,j; + for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(arx, ary, arx+arw-1, ary+arh-1); + bitmap = bitmap + bmp_offy*w + bmp_offx; + for (int row=0;row> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + bits = *charpt++; + //digitalWrite(_dc, 1); + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + x +=8; + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + else { + drawText(x, y, text, fgcolor, bgcolor, doublesize); + } +} + + +/*********************************************************************************************** + DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreen(uint16_t color) { + int i,j; + if (gfxmode < MODE_VGA_320x240) { + for (j=0; j> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + dst=&tft_buffer[l*tft_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + x +=8; + } + } + else { + vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); + vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); + vga_pixel * dst; + while ((c = *text++)) { + const unsigned char * charpt=&font8x8[c][0]; + int l=y; + for (int i=0;i<8;i++) + { + unsigned char bits; + if (doublesize) { + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + x +=8; + } + } +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { + drawSprite(x,y,bitmap, 0,0,0,0); +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) +{ + int bmp_offx = 0; + int bmp_offy = 0; + uint16_t *bmp_ptr; + int w =*bitmap++; + int h = *bitmap++; + if ( (arw == 0) || (arh == 0) ) { + // no crop window + arx = x; + ary = y; + arw = w; + arh = h; + } + else { + if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + int l=ary; + bitmap = bitmap + bmp_offy*w + bmp_offx; + + if (gfxmode < MODE_VGA_320x240) { + for (int row=0;row tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]; + pos +=step; + } + #endif + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i 2) ) y += (tft_height-height)/2; + uint16_t * dst=&tft_buffer[y*tft_stride]; + if (width > tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]]; + pos +=step; + } +#endif + } + else if ((width*2) == tft_width) { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]]; + *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i tft_width) { + int step = ((width << 8)/tft_width); + int pos = 0; + for (int i=0; i> 8]]; + pos +=step; + } + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = pix; + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i +#include +#endif + +#include "platform_config.h" +#include "iopins.h" + + + +#ifndef TFT_WIDTH +#define TFT_WIDTH 320 +#endif +#define TFT_REALWIDTH 320 + +#ifndef TFT_HEIGHT +#define TFT_HEIGHT 240 +#endif +#define TFT_REALHEIGHT 240 + + +typedef enum gfx_mode_t +{ + MODE_UNDEFINED = 0, + MODE_TFTILI_320x240 = 1, + MODE_TFTST_320x240 = 2, + MODE_VGA_320x240 = 3, + MODE_VGA_320x480 = 4, + MODE_VGA_352x240 = 5, + MODE_VGA_352x480 = 6, + MODE_VGA_512x240 = 7, + MODE_VGA_512x480 = 8, + MODE_VGA_640x240 = 9, + MODE_VGA_640x480 = 10 +} gfx_mode_t; + +typedef enum gfx_error_t +{ + GFX_OK = 0, + GFX_ERROR = -1 +} gfx_error_t; + + +#ifdef __cplusplus + +class T4_DSP +{ + public: + T4_DSP(); + + gfx_error_t begin(gfx_mode_t mode); + gfx_mode_t getMode(void); + void startRefresh(void); + void stopRefresh(); + + int get_frame_buffer_size(int *width, int *height); + void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); + + // wait next Vsync + void waitSync(); + void waitLine(int line); + + // NoDMA functions + void fillScreenNoDma(uint16_t color); + void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + // DMA functions + void fillScreen(uint16_t color); + void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + void writeLine(int width, int height, int y, uint16_t *buf); + void writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + void writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16); + void writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + + protected: + static uint8_t _rst, _cs, _dc; + static uint8_t _mosi, _sclk; + static uint8_t _vsync_pin; + static DMAChannel flexio1DMA; + static DMAChannel flexio2DMA; + void tft_setup(bool isST); + static void TFT_isr(void); + static void QT3_isr(void); +}; + +#endif +#endif diff --git a/MCUME_teensy41/teensygen/teensygen.ino b/MCUME_teensy41/teensygen/teensygen.ino index 6238b07..1dd7986 100644 --- a/MCUME_teensy41/teensygen/teensygen.ino +++ b/MCUME_teensy41/teensygen/teensygen.ino @@ -3,132 +3,16 @@ extern "C" { #include "emuapi.h" } -#include "emu.h" -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -TFT_T_DMA tft; -#else -#include "tft_t_dma.h" -TFT_T_DMA tft = TFT_T_DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, TFT_TOUCH_CS, TFT_TOUCH_INT); -#endif - -bool vgaMode = false; - -static unsigned char palette8[PALETTE_SIZE]; -static unsigned short palette16[PALETTE_SIZE]; -static IntervalTimer myTimer; -volatile boolean vbl=true; -static int skip=0; -static elapsedMicros tius; - -static void vblCount() { - if (vbl) { - vbl = false; - } else { - vbl = true; - } -} - -void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) -{ - if (index>8, - 320 & 0xFF, // YEND = 320 - ST7735_INVON , DELAY, // 7: hack - 10, - ST7735_NORON , DELAY, // 8: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 9: Main screen turn on, no args, w/delay - 255 -#endif -}; - -static void dmaInterrupt() { - dmatx.clearInterrupt(); - curTransfer++; - if (curTransfer >= nbTransfer) { - curTransfer = 0; - if (cancelled) { - dmatx.disable(); - rstop = 1; - } - } - arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2); -} - -static void setDmaStruct() { - uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; - int i=0; - uint16_t col=RGBVAL16(0x00,0x00,0x00);; - while (remaining > 0) { - uint16_t * fb = blocks[i]; - int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining); -#ifdef TFT_DEBUG - Serial.println((unsigned long)blocks[i]); - Serial.println(remaining); -#endif - switch (i) { - case 0: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb0[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0x00); -#endif - break; - case 1: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb1[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0xff); -#endif - break; - case 2: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb2[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0x00,0xff); -#endif - break; - case 3: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb3[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0xff,0x00,0xff); -#endif - break; - } - blocks[i] = fb; - if (blocks[i] == 0) { - Serial.print("ILI9341 allocaltion failed for block "); - Serial.println(i); - delay(10000); - } - - for (int j=0;jATTR_DST = 1; - dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); - dmasettings[i].interruptAtCompletion(); - remaining -= len; - i++; - } - dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); - nbTransfer = i; -#ifdef TFT_DEBUG - Serial.println(nbTransfer); -#endif -} - - -TFT_T_DMA::TFT_T_DMA(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso, uint8_t touch_cs, uint8_t touch_irq) -{ - _cs = cs; - _dc = dc; - _rst = rst; - _mosi = mosi; - _sclk = sclk; - _miso = miso; - pinMode(_dc, OUTPUT); - pinMode(_cs, OUTPUT); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); - if ( (touch_cs != 255) && (touch_irq != 255) ) { - _touch_irq = touch_irq; - _touch_cs = touch_cs; - pinMode(_touch_cs, OUTPUT); - pinMode(touch_irq, INPUT_PULLUP); - digitalWrite(_touch_cs, 1); - } -} - - -void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { - int dx=0; - int dy=0; -#ifdef ST7789 - if (TFT_REALWIDTH == TFT_REALHEIGHT) - { -#ifdef ROTATE_SCREEN - if (!flipped) { - dy += 80; - } -#else - if (flipped) { - dx += 80; - } -#endif - } -#endif - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - SPI.transfer16(x1+dx); - digitalWrite(_dc, 1); - SPI.transfer16(x2+dx); - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - digitalWrite(_dc, 1); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - return; - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - - SPI.transfer16(x1+dx); - SPI.transfer16(x2+dx); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - -void TFT_T_DMA::begin(void) { - SPI.setMOSI(_mosi); - SPI.setMISO(_miso); - SPI.setSCK(_sclk); - SPI.begin(); - - // Initialize display - if (_rst != 0xff) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - const uint8_t *addr = init_commands; - digitalWrite(_cs, 0); -#ifdef ILI9341 - while (1) { - uint8_t count = *addr++; - if (count-- == 0) break; - - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - - while (count-- > 0) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - } - - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(ILI9341_DISPON); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); -#endif -#ifdef ST7789 - uint8_t numCommands, numArgs; - uint16_t ms; - numCommands = *addr++; // Number of commands to follow - while(numCommands--) { // For each command... - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - numArgs = *addr++; // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs > 1) { // For each argument... - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - numArgs--; - } - - if (numArgs) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - if(ms) { - ms = *addr++; // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - digitalWrite(_cs, 1); - SPI.endTransaction(); - delay(ms); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - } - } - digitalWrite(_cs, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - SPI.endTransaction(); - - cancelled = false; - -#ifdef FLIP_SCREEN - flipscreen(true); -#else - flipscreen(false); -#endif -#ifdef ST7789 - if (TFT_REALWIDTH != TFT_REALHEIGHT) - { - flipscreen(true); - } -#endif -}; - - - -void TFT_T_DMA::flipscreen(bool flip) -{ - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(TFT_MADCTL); - digitalWrite(_dc, 1); - if (flip) { - flipped=true; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB); -#endif -#endif - } - else { - flipped=false; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB); -#endif -#endif - } - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - -boolean TFT_T_DMA::isflipped(void) -{ - return(flipped); -} - - -#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) - - -void TFT_T_DMA::startDMA(void) { - curTransfer = 0; - rstop = 0; - //dmatx.begin(true); - dmatx.attachInterrupt(dmaInterrupt); - setDmaStruct(); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - - digitalWrite(_cs, HIGH); - SPI.begin(); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); - - - LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: - LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX - LPSPIP_TCR = 15; // Framesize 16 Bits - //LPSPIP_FCR = 0; // Fifo Watermark - LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable - LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: - dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); - - dmatx = dmasettings[0]; - digitalWrite(_cs, 0); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - dmatx.enable(); -} - - -void TFT_T_DMA::stopDMA(void) { - rstop = 0; - wait(); - delay(50); - cancelled = false; - dmatx.detachInterrupt(); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - SPI.end(); -#ifdef ST7789 - begin(); -#endif -#ifdef ILI9341 - SPI.begin(); - digitalWrite(_cs, 0); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - SPI.endTransaction(); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); -} - -void TFT_T_DMA::wait(void) { - rstop = 1; - unsigned long m = millis(); - cancelled = true; - while (!rstop) { - if ((millis() - m) > 100) break; - delay(10); - asm volatile("wfi"); - }; - rstop = 0; -} - -int TFT_T_DMA::get_frame_buffer_size(int *width, int *height){ - if (width != nullptr) *width = TFT_REALWIDTH; - if (height != nullptr) *height = TFT_REALHEIGHT; - return TFT_REALWIDTH; -} - - -/*********************************************************************************************** - Touch functions - ***********************************************************************************************/ -/* Code based on ... - * - * @file XPT2046.cpp - * @date 19.02.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the XPT2046 driver for Arduino. - */ - -#define ADC_MAX 0x0fff - -void TFT_T_DMA::enableTouchIrq() -{ - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 }; - SPI.transfer((void*)&buf[0],3); - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); -} - -//Default callibration for non flipped -#define TX_MIN 30 -#define TY_MIN 20 -#define TX_MAX 300 -#define TY_MAX 220 - -//Default callibration for flipped -#define TFX_MIN 20 -#define TFY_MIN 25 -#define TFX_MAX 288 -#define TFY_MAX 221 - -static uint16_t txMin; -static uint16_t tyMin; -static uint16_t txMax; -static uint16_t tyMax; - - -void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { - if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) { - txMin = xMin; - tyMin = yMin; - txMax = xMax; - tyMax = yMax; - } - else { - if (flipped) { - txMin = TFX_MIN; - tyMin = TFY_MIN; - txMax = TFX_MAX; - tyMax = TFY_MAX; - } - else { - txMin = TX_MIN; - tyMin = TY_MIN; - txMax = TX_MAX; - tyMax = TY_MAX; - } - } -} - - -void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - if ( TOUCH_ENABLED() ) { - uint16_t x = 0; - uint16_t y = 0; - uint16_t z1 = 0; - uint16_t z2 = 0; - uint8_t i = 0; - int16_t xraw=0, yraw=0; - - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - - for(; i < 15; i++) { - // SPI requirer 32bit aliment - uint8_t buf[12] = { - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00 - }; - SPI.transfer(&buf[0], &buf[0], 12); - y += (buf[1] << 8 | buf[2])>>3; - x += (buf[4] << 8 | buf[5])>>3; - z1 += (buf[7] << 8 | buf[8])>>3; - z2 += (buf[10] << 8 | buf[11])>>3; - } - enableTouchIrq(); - - if(i == 0) { - *oX = 0; - *oY = 0; - *oZ = 0; - } - else { - x /= i; - y /= i; - z1 /= i; - z2 /= i; - } - - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); - int z = z1 + ADC_MAX - z2; - if (flipped) { - xraw = x; - yraw = y; - } else { - xraw = ADC_MAX - x; - yraw = ADC_MAX - y; - } - xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1); - yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1); - - *oX = xraw; - *oY = yraw; - *oZ = z; - } - else - { - *oX = 0; - *oY = 0; - *oZ = 0; - } -} - -void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - readRaw(oX,oY,oZ); - // callibrate ... - if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin); - if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin); - //Serial.print(*oX); - //Serial.print(" "); - //Serial.println(*oY); -} - - -/*********************************************************************************************** - No DMA functions - ***********************************************************************************************/ -void TFT_T_DMA::fillScreenNoDma(uint16_t color) { - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - int i,j; - for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(arx, ary, arx+arw-1, ary+arh-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - bits = *charpt++; - //digitalWrite(_dc, 1); - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - x +=8; -#ifdef ILI9341 - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); -#endif - digitalWrite(_cs, 1); - SPI.endTransaction(); - } - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - - - -/*********************************************************************************************** - DMA functions - ***********************************************************************************************/ -uint16_t * TFT_T_DMA::getLineBuffer(int j) -{ - uint16_t * block=blocks[j>>6]; - return(&block[(j&0x3F)*TFT_REALWIDTH]); -} - -void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) { - uint8_t *buffer=buf; - uint8_t *src; - - int i,j,y=0; - if (width*2 <= TFT_REALWIDTH) { - for (j=0; j>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH]; - for (i=0; i>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x]; - for (i=0; i>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - block=blocks[l>>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt++; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - x +=8; - } -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { - drawSprite(x,y,bitmap, 0,0,0,0); -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) -{ - int bmp_offx = 0; - int bmp_offy = 0; - uint16_t *bmp_ptr; - - int w =*bitmap++; - int h = *bitmap++; - - - if ( (arw == 0) || (arh == 0) ) { - // no crop window - arx = x; - ary = y; - arw = w; - arh = h; - } - else { - if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - int l=ary; - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx]; - bmp_ptr = (uint16_t*)bitmap; - for (int col=0;col -#include -#include -#endif - -#include "tft_t_dma_config.h" - -#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) -#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define R16(rgb) ((rgb>>8)&0xf8) -#define G16(rgb) ((rgb>>3)&0xfc) -#define B16(rgb) ((rgb<<3)&0xf8) - -#define PAL_COLOR_MASK 0xff - -#ifdef LOHRES -#define TFT_WIDTH 240 -#define TFT_REALWIDTH 240 -#else -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 -#endif -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - -//#define WIDTH 272 -//#define HEIGHT 228 - -#define LINES_PER_BLOCK 64 -#define NR_OF_BLOCK 4 -#define SCREEN_DMA_NUM_SETTINGS NR_OF_BLOCK - - -#ifdef ILI9341 - -#define ILI9341_NOP 0x00 -#define ILI9341_SWRESET 0x01 -#define ILI9341_RDDID 0x04 -#define ILI9341_RDDST 0x09 - -#define ILI9341_SLPIN 0x10 -#define ILI9341_SLPOUT 0x11 -#define ILI9341_PTLON 0x12 -#define ILI9341_NORON 0x13 - -#define ILI9341_RDMODE 0x0A -#define ILI9341_RDMADCTL 0x0B -#define ILI9341_RDPIXFMT 0x0C -#define ILI9341_RDIMGFMT 0x0D -#define ILI9341_RDSELFDIAG 0x0F - -#define ILI9341_INVOFF 0x20 -#define ILI9341_INVON 0x21 -#define ILI9341_GAMMASET 0x26 -#define ILI9341_DISPOFF 0x28 -#define ILI9341_DISPON 0x29 - -#define ILI9341_CASET 0x2A -#define ILI9341_PASET 0x2B -#define ILI9341_RAMWR 0x2C -#define ILI9341_RAMRD 0x2E - -#define ILI9341_PTLAR 0x30 -#define ILI9341_MADCTL 0x36 -#define ILI9341_VSCRSADD 0x37 -#define ILI9341_PIXFMT 0x3A - -#define ILI9341_FRMCTR1 0xB1 -#define ILI9341_FRMCTR2 0xB2 -#define ILI9341_FRMCTR3 0xB3 -#define ILI9341_INVCTR 0xB4 -#define ILI9341_DFUNCTR 0xB6 - -#define ILI9341_PWCTR1 0xC0 -#define ILI9341_PWCTR2 0xC1 -#define ILI9341_PWCTR3 0xC2 -#define ILI9341_PWCTR4 0xC3 -#define ILI9341_PWCTR5 0xC4 -#define ILI9341_VMCTR1 0xC5 -#define ILI9341_VMCTR2 0xC7 - -#define ILI9341_RDID1 0xDA -#define ILI9341_RDID2 0xDB -#define ILI9341_RDID3 0xDC -#define ILI9341_RDID4 0xDD - -#define ILI9341_GMCTRP1 0xE0 -#define ILI9341_GMCTRN1 0xE1 - -#define ILI9341_MADCTL_MY 0x80 -#define ILI9341_MADCTL_MX 0x40 -#define ILI9341_MADCTL_MV 0x20 -#define ILI9341_MADCTL_ML 0x10 -#define ILI9341_MADCTL_RGB 0x00 -#define ILI9341_MADCTL_BGR 0x08 -#define ILI9341_MADCTL_MH 0x04 - -#define TFT_CASET ILI9341_CASET -#define TFT_PASET ILI9341_PASET -#define TFT_RAMWR ILI9341_RAMWR -#define TFT_MADCTL ILI9341_MADCTL - -#endif - - -#ifdef ST7789 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_RGB 0x00 -#define ST77XX_MADCTL_BGR 0x08 -#define ST77XX_MADCTL_MH 0x04 - -#define TFT_CASET ST7735_CASET -#define TFT_PASET ST7735_RASET -#define TFT_RAMWR ST7735_RAMWR -#define TFT_MADCTL ST7735_MADCTL - -#endif - - - -#ifdef __cplusplus - -class TFT_T_DMA -{ - public: - TFT_T_DMA(uint8_t _CS, uint8_t _DC, uint8_t _RST = 255, uint8_t _MOSI=11, uint8_t _SCLK=13, uint8_t _MISO=12, uint8_t touch_cs=38, uint8_t touch_irq=37); - - void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); - void begin(void); - void flipscreen(bool flip); - boolean isflipped(void); - void startDMA(void); - void stopDMA(); - int get_frame_buffer_size(int *width, int *height); - - // Touch screen functions - #define TOUCH_ENABLED() ((_touch_cs != 255) && (_touch_irq != 255)) - bool isTouching(void) { return ((!TOUCH_ENABLED())?false:(digitalRead(_touch_irq) == LOW)); } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax); - - // NoDMA functions - void writeScreenNoDma(const uint16_t *pcolors); - void fillScreenNoDma(uint16_t color); - void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - // DMA functions - uint16_t * getLineBuffer(int j); - void writeScreen(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int y, uint16_t *buf); - void fillScreen(uint16_t color); - void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - protected: - uint8_t _rst, _cs, _dc; - uint8_t _miso, _mosi, _sclk; - uint8_t _touch_irq=255, _touch_cs=255; - bool flipped=false; - - void wait(void); - void enableTouchIrq(); -}; - -#endif -#endif - - diff --git a/MCUME_teensy41/teensygen/tft_t_dma_config.h b/MCUME_teensy41/teensygen/tft_t_dma_config.h deleted file mode 100644 index 0a712da..0000000 --- a/MCUME_teensy41/teensygen/tft_t_dma_config.h +++ /dev/null @@ -1,13 +0,0 @@ -#include "platform_config.h" - -//#define ST7789 1 -//#define ILI9341 1 - -#define TFT_LINEARINT 1 -#define LINEARINT_HACK 1 - -//#define FLIP_SCREEN 1 -//#define TFT_DEBUG 1 -#if defined(__IMXRT1052__) || defined(__IMXRT1062__) -//#define TFT_STATICFB 1 -#endif diff --git a/MCUME_teensy41/teensygen/vga_t_dma.h b/MCUME_teensy41/teensygen/vga_t_dma.h deleted file mode 100644 index 81a986b..0000000 --- a/MCUME_teensy41/teensygen/vga_t_dma.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - Wrapping class to extend VGA_T4 to TFT_T_DMA -*/ - -#ifndef _VGA_T_DMAH_ -#define _VGA_T_DMAH_ - -#ifdef __cplusplus -#include -#endif - - -#define RGBVAL16(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) - - - - -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 - -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - - - -#ifdef __cplusplus - -class TFT_T_DMA: public VGA_T4 -{ - public: - // Fake touch screen functions - bool isTouching(void) { return false; } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { } - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { }; - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { } - - // fake DMA functions - void startDMA(void) { }; - void stopDMA(void) { }; - - // fake no DMA functions - void writeScreenNoDma(const vga_pixel *pcolors) { writeScreen(pcolors); } - void fillScreenNoDma(vga_pixel color) { clear(color); } - void drawTextNoDma(int16_t x, int16_t y, const char * text, vga_pixel fgcolor, vga_pixel bgcolor, bool doublesize) { drawText(x,y,text,fgcolor,bgcolor,doublesize); } - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, vga_pixel color) { drawRect(x, y, w, h, color); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap) { drawSprite(x, y, bitmap); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh) { drawSprite(x, y, bitmap, croparx, cropary, croparw, croparh); } -}; - - -#endif -#endif diff --git a/MCUME_teensy41/teensygen/emu.cpp b/MCUME_teensy41/teensygen/wrapemu.cpp similarity index 84% rename from MCUME_teensy41/teensygen/emu.cpp rename to MCUME_teensy41/teensygen/wrapemu.cpp index 7f30583..6e7d990 100644 --- a/MCUME_teensy41/teensygen/emu.cpp +++ b/MCUME_teensy41/teensygen/wrapemu.cpp @@ -1,16 +1,15 @@ #include #include "emuapi.h" -#include "tft_t_dma.h" #include "iopins.h" extern "C" { #include "shared.h" #include "system.h" } +#include "arduinoproto.h" - -EXTMEM static unsigned char MemPool[8*1024*1024]; +unsigned char * MemPool = NULL; extern "C" uint8 read_rom(int address) { return (MemPool[address]); @@ -80,9 +79,11 @@ void gen_Init(void) { emu_printf("Allocating MEM"); - bg_pattern_cache = emu_Malloc(BGPATTERN_CACH_SIZE); - work_ram = &MemPool[7*1024*1024]; // emu_Malloc(WORK_RAM_SIZE); - vram = &MemPool[7*1024*1024+WORK_RAM_SIZE];//emu_Malloc(VRAM_SIZE); + bg_pattern_cache = emu_Malloc(BGPATTERN_CACH_SIZE); + + MemPool = emu_SMalloc(5*1024*1024); + work_ram = emu_SMalloc(WORK_RAM_SIZE); //&MemPool[7*1024*1024]; // emu_Malloc(WORK_RAM_SIZE); + vram = emu_SMalloc(VRAM_SIZE); //&MemPool[7*1024*1024+WORK_RAM_SIZE];//emu_Malloc(VRAM_SIZE); zram = emu_Malloc(Z_RAM_SIZE); //mem_init(); @@ -146,11 +147,8 @@ void gen_Start(char * filename) system_init(); -#ifdef SOUND_PRESENT #ifdef HAS_SND - audio_init(22050); - emu_sndInit(); -#endif + audio_init(22050); #endif system_reset(); @@ -166,25 +164,30 @@ void gen_Step(void) { int hk = ihk; if (iusbhk) hk = iusbhk; - if (( k & MASK_JOY1_RIGHT) || ( k & MASK_JOY2_RIGHT)) { - input.pad[0] |= INPUT_RIGHT; - } if (( k & MASK_JOY1_LEFT) || ( k & MASK_JOY2_LEFT)) { input.pad[0] |= INPUT_LEFT; } + if (( k & MASK_JOY1_RIGHT) || ( k & MASK_JOY2_RIGHT)) { + input.pad[0] |= INPUT_RIGHT; + } if (( k & MASK_JOY1_UP) || ( k & MASK_JOY2_UP)) { input.pad[0] |= INPUT_UP; } if (( k & MASK_JOY1_DOWN) || ( k & MASK_JOY2_DOWN)) { input.pad[0] |= INPUT_DOWN; } - if ( k & MASK_JOY2_BTN) { + if (( k & MASK_JOY2_BTN) || ( k & MASK_JOY1_BTN)) { input.pad[0] |= INPUT_A; } if (k & MASK_KEY_USER1) input.pad[0] |= INPUT_C; - if ( (k & MASK_KEY_USER2) || (hk == 'q') ) input.pad[0] |= INPUT_START; - //if (k & MASK_KEY_USER3) input.pad[0] |= INPUT_B; +#ifdef TEECOMPUTER + if (k & MASK_KEY_USER2) input.pad[0] |= INPUT_B; + if (hk == 'q') input.pad[0] |= INPUT_START; +#else + if (k & MASK_KEY_USER2) input.pad[0] |= INPUT_START; + if (k & MASK_KEY_USER3) input.pad[0] |= INPUT_B; +#endif prevhk = hk; @@ -195,9 +198,7 @@ void gen_Step(void) { } void SND_Process(void *stream, int len) { -#ifdef SOUND_PRESENT #ifdef HAS_SND audio_play_sample(stream, 0, len); #endif -#endif } diff --git a/MCUME_teensy41/teensygen/emu.h b/MCUME_teensy41/teensygen/wrapemu.h similarity index 65% rename from MCUME_teensy41/teensygen/emu.h rename to MCUME_teensy41/teensygen/wrapemu.h index 960a514..efc8e71 100644 --- a/MCUME_teensy41/teensygen/emu.h +++ b/MCUME_teensy41/teensygen/wrapemu.h @@ -1,5 +1,10 @@ +#ifdef __cplusplus +extern "C" { +#endif extern void gen_Init(void); extern void gen_Step(void); extern void gen_Start(char * filename); extern void gen_Input(int click); - +#ifdef __cplusplus +} +#endif diff --git a/MCUME_teensy41/teensyhandy/emuapi.cpp b/MCUME_teensy41/teensyhandy/emuapi.cpp index 78c6cc1..e128cca 100644 --- a/MCUME_teensy41/teensyhandy/emuapi.cpp +++ b/MCUME_teensy41/teensyhandy/emuapi.cpp @@ -5,25 +5,31 @@ extern "C" { #include "iopins.h" } -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#else -#include "tft_t_dma.h" -#endif +#include -#ifdef HAS_USBKEY +#ifdef HAS_USB #include "USBHost_t36.h" // Read this header first for key info USBHost myusb; USBHub hub1(myusb); +#ifdef HAS_USBKEY KeyboardController keyboard1(myusb); USBHIDParser hid1(myusb); MouseController mouse1(myusb); +#endif +#ifdef HAS_USBMIDI MIDIDevice midi1(myusb); #endif +#ifdef HAS_USBJOY +#define COUNT_JOYSTICKS 4 +JoystickController joysticks[COUNT_JOYSTICKS](myusb); +#endif +#endif static bool emu_writeConfig(void); static bool emu_readConfig(void); static bool emu_eraseConfig(void); +static bool emu_writeGfxConfig(char * display_type); +static int emu_readGfxConfig(void); static bool mouseDetected = false; static bool keyboardDetected = false; @@ -34,6 +40,7 @@ static File file; #define MAX_FILES 64 #define AUTORUN_FILENAME "autorun.txt" +#define GFX_CFG_FILENAME "gfxmode.txt" #define MAX_FILENAME_SIZE 34 #define MAX_MENULINES 9 @@ -53,7 +60,8 @@ static File file; #define MENU_VGA_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) #define MENU_VGA_YOFFSET (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37) -extern TFT_T_DMA tft; +#include "t4_dsp.h" +T4_DSP tft; static int nbFiles=0; static int curFile=0; @@ -65,6 +73,8 @@ static char selected_filename[MAX_FILENAME_SIZE]=""; static char second_selected_filename[MAX_FILENAME_SIZE]=""; static bool menuRedraw=true; static bool autorun=false; +static bool vgahires=false; + static const unsigned short * keys; #ifdef TEECOMPUTER @@ -103,7 +113,7 @@ void emu_printf(int val) void emu_printi(int val) { - Serial.println(val); + Serial.println(val,HEX); } void emu_printh(int val) @@ -158,7 +168,7 @@ void emu_Free(void * pt) free(pt); } -#define SMEMPOOL (0x400000+400000) +#define SMEMPOOL (0x800000) EXTMEM static unsigned char slowmem[SMEMPOOL]; static int slowmempt = 0; @@ -352,9 +362,10 @@ int emu_ReadKeys(void) #endif if ( row & 0x02 ) retval |= MASK_JOY2_BTN; + #ifdef EXTPAD - if ( fn_pressed ) retval |= MASK_KEY_USER1; if ( sh_pressed ) retval |= MASK_KEY_USER3; + if ( fn_pressed ) retval |= MASK_KEY_USER1; digitalWrite(KLED, 0); #else // Handle LED flash @@ -482,8 +493,10 @@ int emu_ReadKeys(void) while (true) { ; } -#endif +#endif } + + emu_GetJoystick(); return (retval); } @@ -636,7 +649,7 @@ int emu_setKeymap(int index) { } int emu_GetMouse(int *x, int *y, int *buts) { -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBKEY) if (mouse1.available()) { *buts = mouse1.getButtons(); *x = mouse1.getMouseX(); @@ -649,7 +662,23 @@ int emu_GetMouse(int *x, int *y, int *buts) { return 0; } -#ifdef HAS_USBKEY +int emu_GetJoystick(void) { +#if defined(HAS_USB) && (HAS_USBJOY) + for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) { + if (joysticks[joystick_index].available()) { + uint64_t axis_mask = joysticks[joystick_index].axisMask(); + uint64_t axis_changed_mask = joysticks[joystick_index].axisChangedMask(); + uint32_t buttons = joysticks[joystick_index].getButtons(); + Serial.printf("Joystick(%d): buttons = %x", joystick_index, buttons); + Serial.println(); + } + } + return 1; +#endif + return 0; +} + +#if defined(HAS_USB) && (HAS_USBKEY) void OnPress(auto key) { keyboardDetected = true; @@ -793,7 +822,7 @@ int emu_KeyboardDetected(void) { return (keyboardDetected?1:0); } -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) static unsigned char midiBuffer[16]; static unsigned char midiLastCmd=0; static int midiDataCnt=0; @@ -801,8 +830,7 @@ static int midiCmdNbParam=0; #endif void emu_MidiOnDataReceived(unsigned char value) { - -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) //Serial.println(value, HEX); //10000000 = 128 = note off //10010000 = 144 = note on @@ -970,6 +998,7 @@ void emu_MidiOnDataReceived(unsigned char value) { /******************************** * Menu file loader UI ********************************/ +#ifdef FILEBROWSER static int readNbFiles(void) { int totalFiles = 0; @@ -999,8 +1028,6 @@ static int readNbFiles(void) { return totalFiles; } - - void backgroundMenu(void) { menuRedraw=true; tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00)); @@ -1010,11 +1037,13 @@ void backgroundMenu(void) { int handleMenu(uint16_t bClick) { if (autorun) { + toggleMenu(false); + menuRedraw=false; return (ACTION_RUN1); } int action = ACTION_NONE; - if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) ) { + if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) || ( bClick & MASK_KEY_USER2 ) ) { char newpath[MAX_FILENAME_PATH]; strcpy(newpath, selection); strcat(newpath, "/"); @@ -1025,17 +1054,31 @@ int handleMenu(uint16_t bClick) File file = SD.open(selection); if (file.isDirectory()) { curFile = 0; - nbFiles = readNbFiles(); + nbFiles = readNbFiles(); + menuRedraw=true; } - else { - action = ACTION_RUN1; + else + { #ifdef TEECOMPUTER - if (key_extmode) { + if ( (key_extmode) || ( key_sh) ) { emu_writeConfig(); } + if ( tft.getMode() < MODE_VGA_320x240) { + if ( bClick & MASK_KEY_USER2 ) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + } + //emu_SwapJoysticks(0); #endif + toggleMenu(false); + menuRedraw=false; + return (ACTION_RUN1); } - menuRedraw=true; } else if ( bClick & MASK_KEY_USER1 ) { menuRedraw=true; @@ -1044,19 +1087,14 @@ int handleMenu(uint16_t bClick) strcat(second_selection, "/"); strcat(second_selection, second_selected_filename); action = ACTION_RUN2; - } - else if ( bClick & MASK_KEY_USER2 ) { - menuRedraw=true; - //action = ACTION_RUN3; - emu_SwapJoysticks(0); - } + } else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) { if (curFile!=0) { menuRedraw=true; curFile--; } } - else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { + else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { if ((curFile-9)>=0) { menuRedraw=true; curFile -= 9; @@ -1071,7 +1109,7 @@ int handleMenu(uint16_t bClick) menuRedraw=true; } } - else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { + else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { if ((curFile<(nbFiles-9)) && (nbFiles)) { curFile += 9; menuRedraw=true; @@ -1128,12 +1166,12 @@ int handleMenu(uint16_t bClick) return (action); } -bool menuActive(void) +int menuActive(void) { - return (menuOn); + return (menuOn?1:0); } -void toggleMenu(bool on) { +void toggleMenu(int on) { if (on) { menuOn=true; backgroundMenu(); @@ -1151,7 +1189,7 @@ char * menuSecondSelection(void) { return (second_selection); } - +#endif /******************************** * OSKB handling @@ -1171,7 +1209,7 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) int i=0; int fb_width,fb_height,fbstride; - tft.get_frame_buffer_size(&fb_width, &fb_height, &fbstride); + fbstride = tft.get_frame_buffer_size(&fb_width, &fb_height); int ypos = (bottom?(fb_height-2*8):0); int line = row + (bottom?2:0); while ((c[1] = *cpt++)) @@ -1180,7 +1218,7 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0); else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff); if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff); - tft.drawTextNoDma(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); + tft.drawText(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); i++; } } @@ -1278,7 +1316,7 @@ int handleOSKB(void) { return retval; } -void toggleOSKB(bool forceon) { +void toggleOSKB(int forceon) { if (forceon) { oskbOn = true; drawOSKB(); @@ -1362,6 +1400,17 @@ int emu_FileRead(void * buf, int size, int handler) #endif } +int emu_FileWrite(void * buf, int size, int handler) +{ +// emu_printf("emu_FileWrite"); +// emu_printi(handler); +#ifdef HCFH + return (file.write(buf, size)); +#else + return (getFileHandler(handler).write(buf, size)); +#endif +} + int emu_FileGetc(int handler) { // emu_printf("FileGetc"); // emu_printi(handler); @@ -1522,6 +1571,48 @@ static bool emu_eraseConfig(void) SD.remove (ROMSDIR "/" AUTORUN_FILENAME); } +static bool emu_writeGfxConfig(char * display_type) +{ + bool retval = false; + SD.remove ("/" GFX_CFG_FILENAME); + if (strcmp(display_type, "VGA")) { + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(display_type, strlen(display_type)) != strlen(display_type)) { + emu_printf("GFX config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + } + return retval; +} + +#define CFG_VGA 0 +#define CFG_ILI 1 +#define CFG_ST 2 + +static int emu_readGfxConfig(void) +{ + int retval = CFG_VGA; // No file = VGA + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + if (filesize == 2) // "ST" + { + retval = CFG_ST; + } + else if (filesize == 3) // "ILI" + { + retval = CFG_ILI; + } + lofile.close(); + } + return retval; +} + /******************************** * File IO compatibility ********************************/ @@ -1703,62 +1794,249 @@ FRESULT f_mkdir (const char* path) /******************************** - * Initialization + * GFX wrapper ********************************/ -void emu_init(void) +static unsigned short palette16[PALETTE_SIZE]; +static IntervalTimer myTimer; +volatile boolean vbl=true; +volatile boolean vgatimervsync=false; +static void (*vblCallback)(void) = nullptr; +static int skip=0; + +static void vblCount() { + if (vbl) { + vbl = false; + } else { + vbl = true; + } +} + +void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) +{ + if (index= MODE_VGA_320x240 ) { + if (vgatimervsync) { + while (vbl==vb) {}; + } + else { + tft.waitSync(); + } + } + else { + while (vbl==vb) {}; + } + if (vblCallback != nullptr) { + vblCallback(); + } +} + +void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride) +{ + if (skip == 0) { + tft.writeScreenPal(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); + } +} +void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLinePal(width,height,line, VBuf, palette16); + } +} + +void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine(width,height,line, VBuf); + } +} + +void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine8(width,height,line, VBuf, palette16); + } +} + +int emu_IsVga(void) +{ + return (tft.getMode() >= MODE_VGA_320x240?1:0); +} + +int emu_IsVgaHires(void) +{ + return (tft.getMode() >= MODE_VGA_640x240?1:0); +} + +int emu_FrameSkip(void) +{ + return skip; +} + + +/******************************** + * AUDIO wrapper +********************************/ +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +AudioPlaySystem mymixer; + +void emu_sndInit() { + Serial.println("sound init"); + mymixer.begin_audio(256, mymixer.snd_Mixer); + mymixer.start(); +} + +void emu_sndPlaySound(int chan, int volume, int freq) +{ + if (chan < 6) { + mymixer.sound(chan, freq, volume); + } + /* + Serial.print(chan); + Serial.print(":" ); + Serial.print(volume); + Serial.print(":" ); + Serial.println(freq); + */ +} + +void emu_sndPlayBuzz(int size, int val) { + mymixer.buzz(size,val); + //Serial.print((val==1)?1:0); + //Serial.print(":"); + //Serial.println(size); +} +#endif + +/******************************** + * Initialization +********************************/ +void emu_init(int hires) { Serial.begin(115200); + vgahires = hires; -#ifdef HAS_USBKEY +#ifdef HAS_USB myusb.begin(); +#ifdef HAS_USBKEY keyboard1.attachPress(OnPress); keyboard1.attachRelease(OnRelease); #endif +#endif - while (!SD.begin(SD_CS)) +#ifdef FILEBROWSER + if (!SD.begin(SD_CS)) { - Serial.println("SD begin failed, retrying..."); - delay(1000); + Serial.println("No SD card detected"); } strcpy(selection,ROMSDIR); - FileHandlersInit(); - nbFiles = readNbFiles(); - - Serial.print("SD initialized, files found: "); Serial.println(nbFiles); +#endif emu_InitJoysticks(); #ifdef SWAP_JOYSTICK - joySwapped = true; + joySwapped = true; #else - joySwapped = false; + joySwapped = false; #endif -#ifdef TEECOMPUTER -#ifndef HAS_T4_VGA - tft.flipscreen(false); -#endif -#endif int keypressed = emu_ReadKeys(); +#ifdef HAS_T4_VGA + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } +#else + int gfx_mode = CFG_VGA; // default +#ifdef FILEBROWSER + gfx_mode = emu_readGfxConfig(); +#endif + // Force VGA if UP pressed + if (keypressed & MASK_JOY2_UP) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("VGA"); +#endif + gfx_mode = CFG_VGA; + } + else { + if (keypressed & MASK_JOY2_LEFT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ST"); +#endif + gfx_mode = CFG_ST; + } + else if (keypressed & MASK_JOY2_RIGHT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ILI"); +#endif + gfx_mode = CFG_ILI; + } + } + if (gfx_mode == CFG_VGA) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + else + { + tft.begin(gfx_mode == CFG_ILI?MODE_TFTILI_320x240:MODE_TFTST_320x240); + } +#endif + if (keypressed & MASK_JOY2_DOWN) { tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) ); tft.drawTextNoDma(64,48, (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); +#ifdef FILEBROWSER emu_eraseConfig(); delay(1000); +#endif } else { +#ifdef FILEBROWSER if (emu_readConfig()) { autorun = true; } +#endif } +#ifdef FILEBROWSER toggleMenu(true); +#endif } -void emu_start(void) +void emu_start(int vblms, void * callback, int forcetimervsync) { + vgatimervsync = forcetimervsync?true:false; + tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); + tft.startRefresh(); + if (callback != nullptr) { + vblCallback = callback; + } + + myTimer.begin(vblCount, vblms); +#ifdef HAS_SND + emu_sndInit(); +#endif usbnavpad = 0; } diff --git a/MCUME_teensy41/teensyhandy/emuapi.h b/MCUME_teensy41/teensyhandy/emuapi.h index c30ea6a..5dd6130 100644 --- a/MCUME_teensy41/teensyhandy/emuapi.h +++ b/MCUME_teensy41/teensyhandy/emuapi.h @@ -2,127 +2,14 @@ #define EMUAPI_H #include "platform_config.h" - -#define CUSTOM_SND 1 -//#define TIMER_REND 1 -#define EXTPAD 1 - -#define EXTRA_HEAP 0x10 - -// Title: < > -#define TITLE " LYNX Emulator " -#define ROMSDIR "lynx" - -#define emu_Init(ROM) { lnx_Init(); lnx_Start(ROM);} -#define emu_Step(x) { lnx_Step(); } -#define emu_Input(x) { lnx_Input(x); } - -#define MAX_FILENAME_PATH 64 -#define NB_FILE_HANDLER 4 -#define PALETTE_SIZE 256 -#define VID_FRAME_SKIP 0x0 -#define TFT_VBUFFER_YCROP 0 -#define SINGLELINE_RENDERING 1 - -#define R32(rgb) ((rgb>>16)&0xff) -#define G32(rgb) ((rgb>>8)&0xff) -#define B32(rgb) (rgb & 0xff) +#include "emucfg.h" #define ACTION_NONE 0 -#define ACTION_MAXKBDVAL 16 -#define ACTION_EXITKBD 128 -#define ACTION_RUN1 129 -#define ACTION_RUN2 130 -#define ACTION_RUN3 131 - - -#ifdef KEYMAP_PRESENT - -#define keylables_map0_0 (char *)"QWERTYUIOP\x1a" -#define keylables_map0_1 (char *)" ASDFGHJKL\x19" -#define keylables_map0_2 (char *)" ZXCVBNM,.;/" -#define keylables_map0_3 (char *)" +\x10-" -const unsigned short key_map0[] = { - 'q','w','E','R','T','Y','U','I','O','P',157, //default C64 uppercase always - 0,'A','S','D','F','G','H','J','K','L',10, - 0,'Z','X','C','V','B','N','M',',','.',';','/', - 0,0,0,0, - 0,'+',' ','-' - }; - -#define keylables_map1_0 (char *)"1234567890 " -#define keylables_map1_1 (char *)" " -#define keylables_map1_2 (char *)" " -#define keylables_map1_3 (char *)" " - -const unsigned short key_map1[] = { - '1','2','3','4','5','6','7','8','9','0',0, // digit keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map2_0 (char *)"!\"#$%^&*()@" -#define keylables_map2_1 (char *)" " -#define keylables_map2_2 (char *)" <>:?" -#define keylables_map2_3 (char *)" =\x10_" -const unsigned short key_map2[] = { - '!','"','#','$','%','^','&','*','(',')','@', // shiftothers - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,'<','>',':','?', - 153,151,150,152, //U L R D - 0,'=',' ','_' - }; - -#define keylables_map3_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " -#define keylables_map3_1 (char *)" " -#define keylables_map3_2 (char *)" " -#define keylables_map3_3 (char *)" " - -const unsigned short key_map3[] = { - 129,130,131,132,133,134,135,136,0,0,0, // function keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map4_0 (char *)"QWERTYUIOP@" -#define keylables_map4_1 (char *)" ASDFGHJKL\x19" -#define keylables_map4_2 (char *)" ZXCVBNM<>:?" -#define keylables_map4_3 (char *)" =\x10_" -const unsigned short key_map4[] = { - 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase - 0,'A','S','D','F','G','H','J','K','L',10, - 0,'Z','X','C','V','B','N','M','<','>',':','?', - 0,0,0,0, - 0,'=',' ','_' - }; - -#define keylables_map5_0 (char *)" " -#define keylables_map5_1 (char *)" " -#define keylables_map5_2 (char *)" " -#define keylables_map5_3 (char *)" " - -const unsigned short key_map5[] = { - 0,0,0,0,0,0,0,0,0,0,0, // extra keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 153,151,150,152, //U L R D - 0,0,' ',0 - }; - -const unsigned short matkeys[] = { - 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 - 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 - 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 - 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN - 0x510,0x010,0x110,0x310, // row 4 - }; - -#endif +#define ACTION_RUN1 1 +#define ACTION_RUN2 2 +#define FORCE_VGATIMERVSYNC 1 +#define SUPPORT_HIRES 1 #define MASK_JOY2_RIGHT 0x0001 #define MASK_JOY2_LEFT 0x0002 @@ -139,13 +26,13 @@ const unsigned short matkeys[] = { #define MASK_JOY1_BTN 0x1000 #define MASK_KEY_USER4 0x2000 +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) #ifdef __cplusplus extern "C" { +extern void emu_init(int hires=0); +extern void emu_start(int vblms, void * callback, int forcetimervsync=0); #endif - -extern void emu_init(void); -extern void emu_start(void); extern void emu_printf(const char * text); extern void emu_printi(int val); extern void emu_printh(int val); @@ -157,6 +44,7 @@ extern void emu_SFree(void * pt); extern int emu_FileOpen(const char * filepath, const char * mode); extern int emu_FileRead(void * buf, int size, int handler); +extern int emu_FileWrite(void * buf, int size, int handler); extern int emu_FileGetc(int handler); extern int emu_FileSeek(int handler, int seek, int origin); extern int emu_FileTell(int handler); @@ -167,26 +55,23 @@ extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size); extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek); extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index); -extern void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride); -extern void emu_DrawLine(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line); extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line); +extern void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride); extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line); -extern void emu_CopyLine(int width, int height, int ysrc, int ydst); extern void emu_DrawVsync(void); extern int emu_FrameSkip(void); -extern void * emu_LineBuffer(int line); -extern int emu_LineStride(void); -extern int emu_LineWidth(void); -extern void emu_tweakVideo(int shiftdelta, int numdelta, int denomdelta); +extern int emu_IsVga(void); +extern int emu_IsVgaHires(void); -extern bool menuActive(void); +extern int menuActive(void); extern char * menuSelection(void); extern char * menuSecondSelection(void); -extern void toggleMenu(bool on); +extern void toggleMenu(int on); extern int handleMenu(unsigned short bClick); extern int handleOSKB(void); -extern void toggleOSKB(bool forceon); +extern void toggleOSKB(int forceon); extern void emu_InitJoysticks(void); extern int emu_SwapJoysticks(int statusOnly); @@ -195,6 +80,7 @@ extern int emu_ReadKeys(void); extern int emu_GetPad(void); extern int emu_GetMouse(int *x, int *y, int *buts); extern int emu_MouseDetected(void); +extern int emu_GetJoystick(void); extern int emu_KeyboardDetected(void); extern int emu_ReadAnalogJoyX(int min, int max); extern int emu_ReadAnalogJoyY(int min, int max); diff --git a/MCUME_teensy41/teensyhandy/emucfg.h b/MCUME_teensy41/teensyhandy/emucfg.h new file mode 100644 index 0000000..d77faff --- /dev/null +++ b/MCUME_teensy41/teensyhandy/emucfg.h @@ -0,0 +1,115 @@ +#ifndef EMUCFG_H +#define EMUCFG_H + +#include "wrapemu.h" + +// Title: < > +#define TITLE " LYNX Emulator " +#define ROMSDIR "lynx" + +#define emu_Init(ROM) { lnx_Init(); lnx_Start(ROM);} +#define emu_Step(x) { lnx_Step(); } +#define emu_Input(x) { lnx_Input(x); } + +#define MAX_FILENAME_PATH 64 +#define NB_FILE_HANDLER 4 + +#define PALETTE_SIZE 1 +#define VID_FRAME_SKIP 0x0 +#define TFT_VBUFFER_YCROP 0 +#define SINGLELINE_RENDERING 1 +#define CUSTOM_SND 1 +//#define TIMER_REND 1 +//#define EXTPAD 1 +#define EXTRA_HEAP 0x10 +#define FILEBROWSER 1 + + +#ifdef KEYMAP_PRESENT + +#define keylables_map0_0 (char *)"QWERTYUIOP\x1a" +#define keylables_map0_1 (char *)" ASDFGHJKL\x19" +#define keylables_map0_2 (char *)" ZXCVBNM,.;/" +#define keylables_map0_3 (char *)" +\x10-" +const unsigned short key_map0[] = { + 'q','w','E','R','T','Y','U','I','O','P',157, //default C64 uppercase always + 0,'A','S','D','F','G','H','J','K','L',10, + 0,'Z','X','C','V','B','N','M',',','.',';','/', + 0,0,0,0, + 0,'+',' ','-' + }; + +#define keylables_map1_0 (char *)"1234567890 " +#define keylables_map1_1 (char *)" " +#define keylables_map1_2 (char *)" " +#define keylables_map1_3 (char *)" " + +const unsigned short key_map1[] = { + '1','2','3','4','5','6','7','8','9','0',0, // digit keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map2_0 (char *)"!\"#$%^&*()@" +#define keylables_map2_1 (char *)" " +#define keylables_map2_2 (char *)" <>:?" +#define keylables_map2_3 (char *)" =\x10_" +const unsigned short key_map2[] = { + '!','"','#','$','%','^','&','*','(',')','@', // shiftothers + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 153,151,150,152, //U L R D + 0,'=',' ','_' + }; + +#define keylables_map3_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " +#define keylables_map3_1 (char *)" " +#define keylables_map3_2 (char *)" " +#define keylables_map3_3 (char *)" " + +const unsigned short key_map3[] = { + 129,130,131,132,133,134,135,136,0,0,0, // function keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map4_0 (char *)"QWERTYUIOP@" +#define keylables_map4_1 (char *)" ASDFGHJKL\x19" +#define keylables_map4_2 (char *)" ZXCVBNM<>:?" +#define keylables_map4_3 (char *)" =\x10_" +const unsigned short key_map4[] = { + 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase + 0,'A','S','D','F','G','H','J','K','L',10, + 0,'Z','X','C','V','B','N','M','<','>',':','?', + 0,0,0,0, + 0,'=',' ','_' + }; + +#define keylables_map5_0 (char *)" " +#define keylables_map5_1 (char *)" " +#define keylables_map5_2 (char *)" " +#define keylables_map5_3 (char *)" " + +const unsigned short key_map5[] = { + 0,0,0,0,0,0,0,0,0,0,0, // extra keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 153,151,150,152, //U L R D + 0,0,' ',0 + }; + +const unsigned short matkeys[] = { + 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 + 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 + 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 + 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN + 0x510,0x010,0x110,0x310, // row 4 + }; + +#endif + +#endif diff --git a/MCUME_teensy41/teensyhandy/mikie.cpp b/MCUME_teensy41/teensyhandy/mikie.cpp index 1f383fa..0fafbc9 100644 --- a/MCUME_teensy41/teensyhandy/mikie.cpp +++ b/MCUME_teensy41/teensyhandy/mikie.cpp @@ -106,7 +106,7 @@ CMikie::CMikie(CSystem& parent, ULONG displayformat, ULONG samplerate) mpRamPointer=NULL; mDisplayFormat=displayformat; mAudioSampleRate=samplerate; - mDisplayPitch=HANDY_SCREEN_STRIDE * sizeof(HandyPixel); + mDisplayPitch=OUTPUT_SCREEN_STRIDE * sizeof(HandyPixel); mUART_CABLE_PRESENT=FALSE; mpUART_TX_CALLBACK=NULL; @@ -840,13 +840,6 @@ void CMikie::BuildPalette() // TPALETTE Spot; -#ifdef HAS_T4_VGA - for(Spot.Index=0;Spot.Index<4096;Spot.Index++) { - mColourMap[Spot.Index]=((Spot.Colours.Red<<4)&0xE0); - mColourMap[Spot.Index]|=((Spot.Colours.Green<<1)&0x1c); - mColourMap[Spot.Index]|=((Spot.Colours.Blue>>2)&003); - } -#else for(Spot.Index=0;Spot.Index<4096;Spot.Index++) { mColourMap[Spot.Index]=((Spot.Colours.Red<<12)&0xf000) | ((Spot.Colours.Red<<8)&0x0800); mColourMap[Spot.Index]|=((Spot.Colours.Green<<7)&0x0780) | ((Spot.Colours.Green<<3)&0x0060); @@ -858,7 +851,6 @@ void CMikie::BuildPalette() mColourMap[i] = mColourMap[i] << 8 | mColourMap[i] >> 8; } } -#endif // Reset screen related counters/vars mTIM_0_CURRENT=0; @@ -882,10 +874,18 @@ inline void CMikie::ResetDisplayPtr() switch(mDisplayRotate) { case MIKIE_ROTATE_L: - mpDisplayCurrent=gPrimaryFrameBuffer+(mDisplayPitch*(HANDY_SCREEN_WIDTH-1)) + sizeof(HandyPixel)*(320-HANDY_SCREEN_HEIGHT*2)/2; +#ifdef DOUBLE_SCREEN + mpDisplayCurrent=gPrimaryFrameBuffer+(mDisplayPitch*(HANDY_SCREEN_WIDTH-1)) + sizeof(HandyPixel)*(OUTPUT_SCREEN_WIDTH-HANDY_SCREEN_HEIGHT*2)/2; +#else + mpDisplayCurrent=gPrimaryFrameBuffer+(mDisplayPitch*(HANDY_SCREEN_WIDTH-1)) + sizeof(HandyPixel)*(OUTPUT_SCREEN_WIDTH-HANDY_SCREEN_HEIGHT)/2; +#endif break; case MIKIE_ROTATE_R: - mpDisplayCurrent=gPrimaryFrameBuffer + sizeof(HandyPixel)*(320 -(320-HANDY_SCREEN_HEIGHT*2)/2); +#ifdef DOUBLE_SCREEN + mpDisplayCurrent=gPrimaryFrameBuffer + sizeof(HandyPixel)*(OUTPUT_SCREEN_WIDTH -(OUTPUT_SCREEN_WIDTH-HANDY_SCREEN_HEIGHT*2)/2); +#else + mpDisplayCurrent=gPrimaryFrameBuffer + sizeof(HandyPixel)*(OUTPUT_SCREEN_WIDTH -(OUTPUT_SCREEN_WIDTH-HANDY_SCREEN_HEIGHT)/2); +#endif break; default: mpDisplayCurrent=gPrimaryFrameBuffer; @@ -953,98 +953,178 @@ inline ULONG CMikie::DisplayRenderLine(void) // Assign the temporary pointer; bitmap_tmp=(HandyPixel*)mpDisplayCurrent; - switch(mDisplayRotate) - { - - case MIKIE_ROTATE_L: - for(loop=0;loop>4].Index]; - *(bitmap_tmp+1)=mColourMap[mPalette[source>>4].Index]; - bitmap_tmp-=HANDY_SCREEN_STRIDE; - } - else - { - mLynxAddr++; - *(bitmap_tmp)=mColourMap[mPalette[source>>4].Index]; - *(bitmap_tmp+1)=mColourMap[mPalette[source>>4].Index]; - bitmap_tmp-=HANDY_SCREEN_STRIDE; - *(bitmap_tmp)=mColourMap[mPalette[source&0x0f].Index]; - *(bitmap_tmp+1)=mColourMap[mPalette[source&0x0f].Index]; - bitmap_tmp-=HANDY_SCREEN_STRIDE; - } - } - mpDisplayCurrent+=2*sizeof(HandyPixel); - break; - case MIKIE_ROTATE_R: - for(loop=0;loop>4].Index]; - *(bitmap_tmp-1)=mColourMap[mPalette[source>>4].Index]; - bitmap_tmp+=HANDY_SCREEN_STRIDE; - } - else - { - mLynxAddr++; - *(bitmap_tmp)=mColourMap[mPalette[source>>4].Index]; - *(bitmap_tmp-1)=mColourMap[mPalette[source>>4].Index]; - bitmap_tmp+=HANDY_SCREEN_STRIDE; - *(bitmap_tmp)=mColourMap[mPalette[source&0x0f].Index]; - *(bitmap_tmp-1)=mColourMap[mPalette[source&0x0f].Index]; - bitmap_tmp+=HANDY_SCREEN_STRIDE; - } - } - mpDisplayCurrent-=2*sizeof(HandyPixel); - break; - - default: - HandyPixel *bitmappt=bitmap_tmp; +#ifdef DOUBLE_SCREEN + switch(mDisplayRotate) + { + + case MIKIE_ROTATE_L: + for(loop=0;loop>4].Index]; + *(bitmap_tmp+1)=mColourMap[mPalette[source>>4].Index]; + bitmap_tmp-=OUTPUT_SCREEN_STRIDE; + } + else + { + mLynxAddr++; + *(bitmap_tmp)=mColourMap[mPalette[source>>4].Index]; + *(bitmap_tmp+1)=mColourMap[mPalette[source>>4].Index]; + bitmap_tmp-=OUTPUT_SCREEN_STRIDE; + *(bitmap_tmp)=mColourMap[mPalette[source&0x0f].Index]; + *(bitmap_tmp+1)=mColourMap[mPalette[source&0x0f].Index]; + bitmap_tmp-=OUTPUT_SCREEN_STRIDE; + } + } + mpDisplayCurrent+=2*sizeof(HandyPixel); + break; + case MIKIE_ROTATE_R: + for(loop=0;loop>4].Index]; + *(bitmap_tmp-1)=mColourMap[mPalette[source>>4].Index]; + bitmap_tmp+=OUTPUT_SCREEN_STRIDE; + } + else + { + mLynxAddr++; + *(bitmap_tmp)=mColourMap[mPalette[source>>4].Index]; + *(bitmap_tmp-1)=mColourMap[mPalette[source>>4].Index]; + bitmap_tmp+=OUTPUT_SCREEN_STRIDE; + *(bitmap_tmp)=mColourMap[mPalette[source&0x0f].Index]; + *(bitmap_tmp-1)=mColourMap[mPalette[source&0x0f].Index]; + bitmap_tmp+=OUTPUT_SCREEN_STRIDE; + } + } + mpDisplayCurrent-=2*sizeof(HandyPixel); + break; + + default: + HandyPixel *bitmappt=bitmap_tmp; + + for(loop=0;loop>4].Index]; + *(bitmappt++)=mColourMap[mPalette[source>>4].Index]; + *(bitmappt+OUTPUT_SCREEN_STRIDE)=mColourMap[mPalette[source>>4].Index]; + *(bitmappt++)=mColourMap[mPalette[source>>4].Index]; + } + else + { + mLynxAddr++; + *(bitmappt+OUTPUT_SCREEN_STRIDE)=mColourMap[mPalette[source>>4].Index]; + *(bitmappt++)=mColourMap[mPalette[source>>4].Index]; + *(bitmappt+OUTPUT_SCREEN_STRIDE)=mColourMap[mPalette[source>>4].Index]; + *(bitmappt++)=mColourMap[mPalette[source>>4].Index]; + *(bitmappt+OUTPUT_SCREEN_STRIDE)=mColourMap[mPalette[source&0x0f].Index]; + *(bitmappt++)=mColourMap[mPalette[source&0x0f].Index]; + *(bitmappt+OUTPUT_SCREEN_STRIDE)=mColourMap[mPalette[source&0x0f].Index]; + *(bitmappt++)=mColourMap[mPalette[source&0x0f].Index]; + } + } + mpDisplayCurrent+=mDisplayPitch*2; + break; + } +#else + switch(mDisplayRotate) + { + + case MIKIE_ROTATE_L: + for(loop=0;loop>4].Index]; + bitmap_tmp-=OUTPUT_SCREEN_STRIDE; + } + else + { + mLynxAddr++; + *(bitmap_tmp)=mColourMap[mPalette[source>>4].Index]; + bitmap_tmp-=OUTPUT_SCREEN_STRIDE; + *(bitmap_tmp)=mColourMap[mPalette[source&0x0f].Index]; + bitmap_tmp-=OUTPUT_SCREEN_STRIDE; + } + } + mpDisplayCurrent+=sizeof(HandyPixel); + break; + case MIKIE_ROTATE_R: + for(loop=0;loop>4].Index]; + bitmap_tmp+=OUTPUT_SCREEN_STRIDE; + } + else + { + mLynxAddr++; + *(bitmap_tmp)=mColourMap[mPalette[source>>4].Index];; + bitmap_tmp+=OUTPUT_SCREEN_STRIDE; + *(bitmap_tmp)=mColourMap[mPalette[source&0x0f].Index]; + bitmap_tmp+=OUTPUT_SCREEN_STRIDE; + } + } + mpDisplayCurrent-=sizeof(HandyPixel); + break; + + default: + HandyPixel *bitmappt=bitmap_tmp; + + for(loop=0;loop>4].Index]; + *(bitmappt++)=mColourMap[mPalette[source>>4].Index]; + } + else + { + mLynxAddr++; + *(bitmappt+OUTPUT_SCREEN_STRIDE)=mColourMap[mPalette[source>>4].Index]; + *(bitmappt++)=mColourMap[mPalette[source>>4].Index]; + *(bitmappt+OUTPUT_SCREEN_STRIDE)=mColourMap[mPalette[source&0x0f].Index]; + *(bitmappt++)=mColourMap[mPalette[source&0x0f].Index]; + } + } + mpDisplayCurrent+=mDisplayPitch*2; + break; + } +#endif - for(loop=0;loop>4].Index]; - *(bitmappt++)=mColourMap[mPalette[source>>4].Index]; - *(bitmappt+HANDY_SCREEN_STRIDE)=mColourMap[mPalette[source>>4].Index]; - *(bitmappt++)=mColourMap[mPalette[source>>4].Index]; - } - else - { - mLynxAddr++; - *(bitmappt+HANDY_SCREEN_STRIDE)=mColourMap[mPalette[source>>4].Index]; - *(bitmappt++)=mColourMap[mPalette[source>>4].Index]; - *(bitmappt+HANDY_SCREEN_STRIDE)=mColourMap[mPalette[source>>4].Index]; - *(bitmappt++)=mColourMap[mPalette[source>>4].Index]; - *(bitmappt+HANDY_SCREEN_STRIDE)=mColourMap[mPalette[source&0x0f].Index]; - *(bitmappt++)=mColourMap[mPalette[source&0x0f].Index]; - *(bitmappt+HANDY_SCREEN_STRIDE)=mColourMap[mPalette[source&0x0f].Index]; - *(bitmappt++)=mColourMap[mPalette[source&0x0f].Index]; - } - } - mpDisplayCurrent+=mDisplayPitch*2; - break; - } } return work_done; } diff --git a/MCUME_teensy41/teensyhandy/platform_config.h b/MCUME_teensy41/teensyhandy/platform_config.h index 3464dc2..914d152 100644 --- a/MCUME_teensy41/teensyhandy/platform_config.h +++ b/MCUME_teensy41/teensyhandy/platform_config.h @@ -4,13 +4,13 @@ #define TEECOMPUTER 1 #ifdef TEECOMPUTER -//#define ILI9341 1 -//#define ST7789 1 -//#define TFTSPI1 1 -#define HAS_T4_VGA 1 +#define TFTSPI1 1 +//#define HAS_T4_VGA 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 -//#define INVX 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 #define PT8211 1 #else @@ -19,7 +19,11 @@ //#define INVX 1 #define INVY 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 +#define PT8211 1 #endif diff --git a/MCUME_teensy41/teensyhandy/system.h b/MCUME_teensy41/teensyhandy/system.h index a6b5065..8a679ab 100644 --- a/MCUME_teensy41/teensyhandy/system.h +++ b/MCUME_teensy41/teensyhandy/system.h @@ -60,11 +60,8 @@ typedef uint16_t UWORD; typedef int32_t SLONG; typedef uint32_t ULONG; -#ifdef HAS_T4_VGA -typedef UBYTE HandyPixel; -#else +//typedef UBYTE HandyPixel; typedef UWORD HandyPixel; -#endif extern ULONG crc32_le(ULONG crc, UBYTE const * buf, ULONG len); @@ -102,8 +99,12 @@ extern ULONG crc32_le(ULONG crc, UBYTE const * buf, ULONG len); #define HANDY_FILETYPE_RAW 4 #define HANDY_SCREEN_WIDTH 160 -#define HANDY_SCREEN_STRIDE emu_LineStride() #define HANDY_SCREEN_HEIGHT 102 + +#define OUTPUT_SCREEN_WIDTH 160 +#define OUTPUT_SCREEN_HEIGHT (HANDY_SCREEN_HEIGHT*2) +#define OUTPUT_SCREEN_STRIDE 160 + // // Define the global variable list // diff --git a/MCUME_teensy41/teensyhandy/t4_dsp.cpp b/MCUME_teensy41/teensyhandy/t4_dsp.cpp new file mode 100644 index 0000000..43301fa --- /dev/null +++ b/MCUME_teensy41/teensyhandy/t4_dsp.cpp @@ -0,0 +1,1774 @@ +/* + TFT/VGA driver + DMA TFT driver based on C64 ILI9341 dma driver from Frank Bösing, 2017 +*/ + +#include "T4_DSP.h" + +#include +#include + +#include "font8x8.h" + +// TFT constants and variables +#define TFT_LINEARINT 1 +#define LINEARINT_HACK 1 +#define DMA_LINES_PER_BLOCK 64 +#define DMA_NUM_SETTINGS 4 + +#define TFT_SWRESET 0x01 +#define TFT_SLPOUT 0x11 +#define TFT_INVON 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_MADCTL 0x36 +#define TFT_PIXFMT 0x3A +#define TFT_MADCTL_MY 0x80 +#define TFT_MADCTL_MX 0x40 +#define TFT_MADCTL_MV 0x20 +#define TFT_MADCTL_ML 0x10 +#define TFT_MADCTL_RGB 0x00 +#define TFT_MADCTL_BGR 0x08 +#define TFT_MADCTL_MH 0x04 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) +//#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) +//#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) +//#define R16(rgb) ((rgb>>8)&0xf8) +//#define G16(rgb) ((rgb>>3)&0xfc) +//#define B16(rgb) ((rgb<<3)&0xf8) + +// LPSPI4 = SPI0 in Teensy 4.0 +// LPSPI3 = SPI1 in Teensy 4.0 +// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) + +#ifdef TFTSPI1 +#define SPI SPI1 +#define LPSPIP_TDR LPSPI3_TDR +#define LPSPIP_CR LPSPI3_CR +#define LPSPIP_CFGR1 LPSPI3_CFGR1 +#define LPSPIP_TCR LPSPI3_TCR +#define LPSPIP_DER LPSPI3_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX +#else +#define LPSPIP_TDR LPSPI4_TDR +#define LPSPIP_CR LPSPI4_CR +#define LPSPIP_CFGR1 LPSPI4_CFGR1 +#define LPSPIP_TCR LPSPI4_TCR +#define LPSPIP_DER LPSPI4_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX +#endif + +#define SPICLOCK 60000000 +#define SPI_MODE SPI_MODE0 + +// VGA constants and macros +typedef uint8_t vga_pixel; +#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) + +static DMASetting dmasettings[DMA_NUM_SETTINGS]; +static DMAChannel dmatx; +static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K +static volatile uint8_t rstop = 0; +static volatile bool cancelled = false; +static volatile uint8_t curTransfer = 0; +static uint8_t nbTransfer = 0; +static uint16_t * tft_buffer; +static int tft_width; +static int tft_height; +static int tft_stride; + +#define DELAY_MASK 0x80 +PROGMEM static const uint8_t init_commands[] = { + 1+DELAY_MASK, TFT_SWRESET, 150, + 1+DELAY_MASK, TFT_SLPOUT, 255, + 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, + 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, + 1, TFT_INVON, + 1, TFT_DISPON, + 0 +}; + +// VGA constants and variables +// Objective: +// generates VGA signal fully in hardware with as little as possible CPU help + +// Principle: +// QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) +// 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate +// RGB out, combined to create 8bits(/12bits) output. + +// Note: +// - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels +// - experimental resolution: 352x240,352x480 +// - experimental resolution: 512x240,512x480 (not stable) +// - video memory is allocated using malloc in T4 heap +// - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing +// but tried to be compensated by pixel shifting +// - Default is 8bits RRRGGGBB (332) +// But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! +// - Only ok at 600MHz else some disturbances visible + + + +#define TOP_BORDER 40 +#define PIN_HBLANK 15 + +#define PIN_R_B2 33 +#define PIN_R_B1 4 +#define PIN_R_B0 3 +#define PIN_G_B2 2 +#define PIN_G_B1 13 +#define PIN_G_B0 11 +#define PIN_B_B1 12 +#define PIN_B_B0 10 + + +#define DMA_HACK 0x80 + +#define R16(rgb) ((rgb>>8)&0xf8) +#define G16(rgb) ((rgb>>3)&0xfc) +#define B16(rgb) ((rgb<<3)&0xf8) + +// VGA 640x480@60Hz +// Screen refresh rate 60 Hz +// Vertical refresh 31.46875 kHz +// Pixel freq. 25.175 MHz +// +// Visible area 640 25.422045680238 us +// Front porch 16 0.63555114200596 us +// Sync pulse 96 3.8133068520357 us +// Back porch 48 1.9066534260179 us +// Whole line 800 31.777557100298 us + +#define frame_freq 60.0 // Hz +#define line_freq 31.46875 // KHz +#define pix_freq (line_freq*800) // KHz (25.175 MHz) + +// pix_period = 39.7ns +// H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) +#define frontporch_pix 20 //16 +#define backporch_pix 44 //48 + +// Flexio Clock +// PLL3 SW CLOCK (3) => 480 MHz +// PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) +#define FLEXIO_CLK_SEL_PLL3 3 +#define FLEXIO_CLK_SEL_PLL5 2 + +/* Set video PLL */ +// There are /1, /2, /4, /8, /16 post dividers for the Video PLL. +// The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, +// and CCM_ANALOG_MISC2 register sets according to the following equation. +// PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + +// nfact: +// This field controls the PLL loop divider. +// Valid range for DIV_SELECT divider value: 27~54. + +#define POST_DIV_SELECT 2 + +// Full buffer including back/front porch +static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; +static uint32_t dstbuffer __attribute__((aligned(32))); + +// Visible vuffer +static vga_pixel * vga_buffer; +static int vga_width; +static int vga_height; +static int vga_stride; + +static int maxpixperline; +static int left_border; +static int right_border; +static int line_double; +static int pix_shift; +static int ref_div_select; +static int ref_freq_num; +static int ref_freq_denom; +static int ref_pix_shift; +static int combine_shiftreg; + +#ifdef DEBUG +static uint32_t ISRTicks_prev = 0; +volatile uint32_t ISRTicks = 0; +#endif + +uint8_t T4_DSP::_rst; +uint8_t T4_DSP::_cs; +uint8_t T4_DSP::_dc; +uint8_t T4_DSP::_mosi; +uint8_t T4_DSP::_sclk; +uint8_t T4_DSP::_vsync_pin = -1; +DMAChannel T4_DSP::flexio1DMA; +DMAChannel T4_DSP::flexio2DMA; + +static volatile uint32_t VSYNC = 0; +static volatile uint32_t currentLine=0; +#define NOP asm volatile("nop\n\t"); +static gfx_mode_t gfxmode = MODE_UNDEFINED; + + +FASTRUN void T4_DSP::TFT_isr(void) { + dmatx.clearInterrupt(); + curTransfer++; + if (curTransfer >= nbTransfer) { + curTransfer = 0; + if (cancelled) { + dmatx.disable(); + rstop = 1; + } + } + arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); +} + +FASTRUN void T4_DSP::QT3_isr(void) { + TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); + TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); + + cli(); + + // V-PULSE + if (currentLine > 0) { + digitalWrite(_vsync_pin, 1); + VSYNC = 0; + } else { + digitalWrite(_vsync_pin, 0); + VSYNC = 1; + } + + currentLine++; + currentLine = currentLine % 525; + + + uint32_t y = (currentLine - TOP_BORDER) >> line_double; + // Visible area + + if (y >= 0 && y < vga_height) { + // Disable DMAs + //DMA_CERQ = flexio2DMA.channel; + //DMA_CERQ = flexio1DMA.channel; + + // Setup source adress + // Aligned 32 bits copy + unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; + flexio2DMA.TCD->SADDR = p; + if (pix_shift & DMA_HACK) + { + // Unaligned copy + uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; + flexio1DMA.TCD->SADDR = p2; + } + else { + p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 + flexio1DMA.TCD->SADDR = p; + } + + // Enable DMAs + //flexio2DMA.enable(); + //flexio1DMA.enable(); + DMA_SERQ = flexio2DMA.channel; + DMA_SERQ = flexio1DMA.channel; + arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); + } + sei(); + +#ifdef DEBUG + ISRTicks++; +#endif + asm volatile("dsb"); +} + +static void setDmaStruct() { + uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; + uint16_t * fb = (uint16_t*)malloc(remaining); + tft_buffer = fb; + tft_width = TFT_WIDTH; + tft_height = TFT_HEIGHT; + tft_stride = TFT_WIDTH; + uint16_t col=RGBVAL16(0x00,0x00,0x00); + int i=0; + while (remaining > 0) { + int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); + blocks[i] = fb; + for (int j=0;jATTR_DST = 1; + dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); + dmasettings[i].interruptAtCompletion(); + fb += len/2; + remaining -= len; + i++; + } + dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); + nbTransfer = i; +} + +static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 +{ +//if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; + CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE + | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 + | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); + CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; + CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock + const int div_post_pll = 1; // other values: 2,4 + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass +} + +T4_DSP::T4_DSP() +{ + _cs = TFT_CS; + _dc = TFT_DC; + _rst = TFT_RST; + _mosi = TFT_MOSI; + _sclk = TFT_SCLK; + pinMode(_dc, OUTPUT); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, 1); + digitalWrite(_dc, 1); + _vsync_pin = 8; +} + + +void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { + int dx=0; + int dy=0; + digitalWrite(_dc, 0); + SPI.transfer(TFT_CASET); + digitalWrite(_dc, 1); + SPI.transfer16(x1+dx); + digitalWrite(_dc, 1); + SPI.transfer16(x2+dx); + digitalWrite(_dc, 0); + SPI.transfer(TFT_PASET); + digitalWrite(_dc, 1); + SPI.transfer16(y1+dy); + digitalWrite(_dc, 1); + SPI.transfer16(y2+dy); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + return; +} + +void T4_DSP::tft_setup(bool isST) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + // RESET if reset pin defined + if (_rst != 0xff) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + const uint8_t *addr = init_commands; + uint8_t count; + digitalWrite(_cs, 0); + while (count = *addr++) { + uint8_t command = *addr++; + if ( (command == TFT_INVON) && (!isST) ) { + // Skip TFT_INVON for ILI + } + else { + digitalWrite(_dc, 0); // command + SPI.transfer(command); + uint16_t ms = count & DELAY_MASK; + count &= ~DELAY_MASK; + while (--count > 0) { // data + uint8_t data = *addr++; + if ( (command == TFT_MADCTL) && (isST) ) { + data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; + } + digitalWrite(_dc, 1); + SPI.transfer(data); + } + if (ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + digitalWrite(_cs, 1); + SPI.endTransaction(); + delay(2); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + } + } + } + digitalWrite(_cs, 1); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + SPI.endTransaction(); + /* + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_dc, 0); + digitalWrite(_cs, 0); + SPI.transfer(TFT_MADCTL); + digitalWrite(_dc, 1); + SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); + // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); + digitalWrite(_cs, 1); + SPI.endTransaction(); + */ + cancelled = false; +} + +// display VGA image +gfx_error_t T4_DSP::begin(gfx_mode_t mode) +{ + uint32_t flexio_clock_div; + combine_shiftreg = 0; +// int div_select = 49; +// int num = 135; +// int denom = 100; + int div_select = 20; + int num = 9800; + int denom = 10000; + int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; + int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; + set_videoClock(div_select,num,denom,true); + +#ifdef DEBUG + Serial.println(mode); + Serial.println("mode"); +#endif + + switch(mode) + { + case MODE_TFTILI_320x240: +#ifdef DEBUG + Serial.println("TFTILI_320x240"); +#endif + tft_setup(false); + gfxmode = mode; + break; + case MODE_TFTST_320x240: +#ifdef DEBUG + Serial.println("TFTST_320x240"); +#endif + tft_setup(true); + gfxmode = mode; + break; + + case MODE_VGA_320x240: +#ifdef DEBUG + Serial.println("VGA_320x240"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_320x480: +#ifdef DEBUG + Serial.println("VGA_320x480"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_640x240: +#ifdef DEBUG + Serial.println("VGA_640x240"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/pix_freq; + line_double = 1; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_640x480: +#ifdef DEBUG + Serial.println("VGA_640x480"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = (flexio_freq/pix_freq); + line_double = 0; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_512x240: +#ifdef DEBUG + Serial.println("VGA_512x240"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 1; + pix_shift = 0; + break; + + case MODE_VGA_512x480: +#ifdef DEBUG + Serial.println("VGA_512x480"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 0; + pix_shift = 0; + break; + + case MODE_VGA_352x240: +#ifdef DEBUG + Serial.println("VGA_352x240"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_352x480: +#ifdef DEBUG + Serial.println("VGA_352x480"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + } + + if (mode >= MODE_VGA_320x240) + { + if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { + fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); + digitalWrite(_cs, 0); + digitalWrite(_dc, 0); + SPI.transfer(TFT_DISPOFF); + digitalWrite(_cs, 1); + delay(20); + digitalWrite(_cs, 0); + digitalWrite(_cs, 1); + } + gfxmode = mode; + + maxpixperline = vga_stride; + // Save param for tweek adjustment + ref_div_select = div_select; + ref_freq_num = num; + ref_freq_denom = denom; + ref_pix_shift = pix_shift; + +#ifdef DEBUG + Serial.println("frequency"); + Serial.println(flexio_freq); + Serial.println("div"); + Serial.println(flexio_freq/pix_freq); +#endif + + pinMode(_vsync_pin, OUTPUT); + pinMode(PIN_HBLANK, OUTPUT); + + /* Basic pin setup FlexIO1 */ + pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 + pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 + pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 + pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 + /* Basic pin setup FlexIO2 */ + pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 + pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 + pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 + pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 + + /* High speed and drive strength configuration */ + *(portControlRegister(PIN_G_B2)) = 0xFF; + *(portControlRegister(PIN_R_B0)) = 0xFF; + *(portControlRegister(PIN_R_B1)) = 0xFF; + *(portControlRegister(PIN_R_B2)) = 0xFF; + *(portControlRegister(PIN_B_B0)) = 0xFF; + *(portControlRegister(PIN_B_B1)) = 0xFF; + *(portControlRegister(PIN_G_B0)) = 0xFF; + *(portControlRegister(PIN_G_B1)) = 0xFF; + + /* Set clock for FlexIO1 and FlexIO2 */ + CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) + | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); + CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) + | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); + + + /* Set up pin mux FlexIO1 */ + *(portConfigRegister(PIN_G_B2)) = 0x14; + *(portConfigRegister(PIN_R_B0)) = 0x14; + *(portConfigRegister(PIN_R_B1)) = 0x14; + *(portConfigRegister(PIN_R_B2)) = 0x14; + /* Set up pin mux FlexIO2 */ + *(portConfigRegister(PIN_B_B0)) = 0x14; + *(portConfigRegister(PIN_B_B1)) = 0x14; + *(portConfigRegister(PIN_G_B0)) = 0x14; + *(portConfigRegister(PIN_G_B1)) = 0x14; + + /* Enable the clock */ + CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + /* Enable the FlexIO with fast access */ + FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + + uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; + uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; + + /* Shifter 0 registers for FlexIO2 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 + inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter + stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled + startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable + timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 + timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock + pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output + pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity + shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode + /* Shifter 0 registers for FlexIO1 */ + FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + /* Shifter 0 registers for FlexIO1 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 + FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + if (combine_shiftreg) { + pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled + FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + } + /* Timer 0 registers for FlexIO2 */ + timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset + timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output + timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset + timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare + timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert + stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled + startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled + if (combine_shiftreg) { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag + } + else { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag + } + triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low + triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected + pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled + //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 + //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high + timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode + // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) + + int shifts_per_transfer; + if (combine_shiftreg) { + shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 + } + else { + shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 + } + FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); + /* Timer 0 registers for FlexIO1 */ + FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); +#ifdef DEBUG + Serial.println("FlexIO setup complete"); +#endif + + /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ + if (combine_shiftreg) { + FLEXIO2_SHIFTSDEN |= (1<<1); + FLEXIO1_SHIFTSDEN |= (1<<1); + } + else { + FLEXIO2_SHIFTSDEN |= (1<<0); + FLEXIO1_SHIFTSDEN |= (1<<0); + } + /* Disable DMA channel so it doesn't start transferring yet */ + flexio1DMA.disable(); + flexio2DMA.disable(); + /* Set up DMA channel to use Shifter 0 trigger */ + flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); + flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); + + + if (combine_shiftreg) { + flexio2DMA.TCD->NBYTES = 8; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 8; + flexio2DMA.TCD->CITER = maxpixperline / 8; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + flexio1DMA.TCD->NBYTES = 8; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 8; + flexio1DMA.TCD->CITER = maxpixperline / 8; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Setup DMA2 Flexio2 copy + flexio2DMA.TCD->NBYTES = 4; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 4; + flexio2DMA.TCD->CITER = maxpixperline / 4; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + // Setup DMA1 Flexio1 copy + // Use pixel shift to avoid color smearing? + if (pix_shift & DMA_HACK) + { + if (pix_shift & 0x3 == 0) { + // Aligned 32 bits copy (32bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Unaligned (source) 32 bits copy (8bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 1; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion + } + } + else + { + // Aligned 32 bits copy + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + } + +#ifdef DEBUG + Serial.println("DMA setup complete"); +#endif + + // enable clocks for QTIMER3: generates the 15KHz for hsync + // Pulse: + // low : 3.8133 us => 569x6.7ns + // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) + // (OLD TEST) + // (4us low, 28us high => 32us) + // (597x6.7ns for 4us) + // (4179x6.7ns for 28us) + CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 + //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 + + #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz + #define MARGIN_D 1000 + + TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer + // Invert output pin as we want the interupt on rising edge + TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) + TMR3_CNTR3 = 0; + TMR3_LOAD3 = 0; + + /* Inverted timings */ + unsigned long long cpu_freq = F_CPU; + unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; + int rate2 = rate; + + int substract = 1; + if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { + substract=5; + rate2=1652; + } + + #ifdef DEBUG + Serial.print("MARGIN_N is: "); + Serial.println(rate2, DEC); + Serial.print("SUBSTRACT is: "); + Serial.println(substract, DEC); +#endif + TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; + TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; + /* + TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; + */ + TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on + TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), + // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) + //configure Teensy pin Compare output + IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 + attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function + NVIC_ENABLE_IRQ(IRQ_QTIMER3); +#ifdef DEBUG + Serial.println("QTIMER3 setup complete"); + Serial.print("V-PIN is "); + Serial.println(_vsync_pin); +#endif + + /* initialize gfx buffer */ + if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift + if (gfxbuffer == NULL) return(GFX_ERROR); +#ifdef DEBUG + Serial.println("Memory allocated"); +#endif + + memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); + vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; +#ifdef DEBUG + Serial.println(vga_stride); + Serial.println(vga_height); + Serial.println("Screen cleared"); +#endif + } + + return(GFX_OK); +} + +gfx_mode_t T4_DSP::getMode(void) +{ + return gfxmode; +} + +void T4_DSP::startRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + curTransfer = 0; + rstop = 0; + //dmatx.begin(true); + dmatx.attachInterrupt(TFT_isr); + setDmaStruct(); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + + digitalWrite(_cs, HIGH); + SPI.begin(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + + LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: + LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX + LPSPIP_TCR = 15; // Framesize 16 Bits + //LPSPIP_FCR = 0; // Fifo Watermark + LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable + LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: + dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); + + dmatx = dmasettings[0]; + digitalWrite(_cs, 0); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + dmatx.enable(); + } +} + + +void T4_DSP::stopRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + rstop = 1; + unsigned long m = millis(); + cancelled = true; + while (!rstop) { + if ((millis() - m) > 100) break; + delay(10); + asm volatile("wfi"); + }; + rstop = 0; + delay(50); + cancelled = false; + dmatx.detachInterrupt(); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + SPI.end(); +#ifdef ST7789 +// begin(gfxmode); +#endif + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + } +} + +int T4_DSP::get_frame_buffer_size(int *width, int *height) { + if (gfxmode < MODE_VGA_320x240) { + if (width != nullptr) *width = tft_width; + if (height != nullptr) *height = tft_height; + return tft_stride; + } + else { + if (width != nullptr) *width = vga_width; + if (height != nullptr) *height = vga_height; + return vga_stride; + } +} + +void T4_DSP::waitSync() +{ + if (gfxmode >= MODE_VGA_320x240) { + while (VSYNC == 0) {}; + } +} + +void T4_DSP::waitLine(int line) +{ + if (gfxmode >= MODE_VGA_320x240) { + while (currentLine != line) {}; + } +} + +/*********************************************************************************************** + No DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreenNoDma(uint16_t color) { + if (gfxmode < MODE_VGA_320x240) { + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + int i,j; + for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(arx, ary, arx+arw-1, ary+arh-1); + bitmap = bitmap + bmp_offy*w + bmp_offx; + for (int row=0;row> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + bits = *charpt++; + //digitalWrite(_dc, 1); + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + x +=8; + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + else { + drawText(x, y, text, fgcolor, bgcolor, doublesize); + } +} + + +/*********************************************************************************************** + DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreen(uint16_t color) { + int i,j; + if (gfxmode < MODE_VGA_320x240) { + for (j=0; j> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + dst=&tft_buffer[l*tft_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + x +=8; + } + } + else { + vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); + vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); + vga_pixel * dst; + while ((c = *text++)) { + const unsigned char * charpt=&font8x8[c][0]; + int l=y; + for (int i=0;i<8;i++) + { + unsigned char bits; + if (doublesize) { + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + x +=8; + } + } +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { + drawSprite(x,y,bitmap, 0,0,0,0); +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) +{ + int bmp_offx = 0; + int bmp_offy = 0; + uint16_t *bmp_ptr; + int w =*bitmap++; + int h = *bitmap++; + if ( (arw == 0) || (arh == 0) ) { + // no crop window + arx = x; + ary = y; + arw = w; + arh = h; + } + else { + if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + int l=ary; + bitmap = bitmap + bmp_offy*w + bmp_offx; + + if (gfxmode < MODE_VGA_320x240) { + for (int row=0;row tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]; + pos +=step; + } + #endif + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i 2) ) y += (tft_height-height)/2; + uint16_t * dst=&tft_buffer[y*tft_stride]; + if (width > tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]]; + pos +=step; + } +#endif + } + else if ((width*2) == tft_width) { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]]; + *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i tft_width) { + int step = ((width << 8)/tft_width); + int pos = 0; + for (int i=0; i> 8]]; + pos +=step; + } + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = pix; + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i +#include +#endif + +#include "platform_config.h" +#include "iopins.h" + + + +#ifndef TFT_WIDTH +#define TFT_WIDTH 320 +#endif +#define TFT_REALWIDTH 320 + +#ifndef TFT_HEIGHT +#define TFT_HEIGHT 240 +#endif +#define TFT_REALHEIGHT 240 + + +typedef enum gfx_mode_t +{ + MODE_UNDEFINED = 0, + MODE_TFTILI_320x240 = 1, + MODE_TFTST_320x240 = 2, + MODE_VGA_320x240 = 3, + MODE_VGA_320x480 = 4, + MODE_VGA_352x240 = 5, + MODE_VGA_352x480 = 6, + MODE_VGA_512x240 = 7, + MODE_VGA_512x480 = 8, + MODE_VGA_640x240 = 9, + MODE_VGA_640x480 = 10 +} gfx_mode_t; + +typedef enum gfx_error_t +{ + GFX_OK = 0, + GFX_ERROR = -1 +} gfx_error_t; + + +#ifdef __cplusplus + +class T4_DSP +{ + public: + T4_DSP(); + + gfx_error_t begin(gfx_mode_t mode); + gfx_mode_t getMode(void); + void startRefresh(void); + void stopRefresh(); + + int get_frame_buffer_size(int *width, int *height); + void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); + + // wait next Vsync + void waitSync(); + void waitLine(int line); + + // NoDMA functions + void fillScreenNoDma(uint16_t color); + void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + // DMA functions + void fillScreen(uint16_t color); + void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + void writeLine(int width, int height, int y, uint16_t *buf); + void writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + void writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16); + void writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + + protected: + static uint8_t _rst, _cs, _dc; + static uint8_t _mosi, _sclk; + static uint8_t _vsync_pin; + static DMAChannel flexio1DMA; + static DMAChannel flexio2DMA; + void tft_setup(bool isST); + static void TFT_isr(void); + static void QT3_isr(void); +}; + +#endif +#endif diff --git a/MCUME_teensy41/teensyhandy/teensyhandy.ino b/MCUME_teensy41/teensyhandy/teensyhandy.ino index 21c4f4b..bbd18d6 100644 --- a/MCUME_teensy41/teensyhandy/teensyhandy.ino +++ b/MCUME_teensy41/teensyhandy/teensyhandy.ino @@ -3,146 +3,20 @@ extern "C" { #include "iopins.h" } -#include "lynx.h" - -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -TFT_T_DMA tft; -#else -#include "tft_t_dma.h" -TFT_T_DMA tft = TFT_T_DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, TFT_TOUCH_CS, TFT_TOUCH_INT); -#endif - -bool vgaMode = false; - -static unsigned char palette8[PALETTE_SIZE]; -static unsigned short palette16[PALETTE_SIZE]; -static IntervalTimer myTimer; -volatile boolean vbl=true; -static int skip=0; -static elapsedMicros tius; -static int fbstride; -static int fbwidth; -static int fbheight; - -static void vblCount() { - if (vbl) { - vbl = false; - } else { - vbl = true; - } -} - -void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) -{ - if (index>8, - 320 & 0xFF, // YEND = 320 - ST7735_INVON , DELAY, // 7: hack - 10, - ST7735_NORON , DELAY, // 8: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 9: Main screen turn on, no args, w/delay - 255 -#endif -}; - -static void dmaInterrupt() { - dmatx.clearInterrupt(); - curTransfer++; - if (curTransfer >= nbTransfer) { - curTransfer = 0; - if (cancelled) { - dmatx.disable(); - rstop = 1; - } - } - arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2); -} - -static void setDmaStruct() { - uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; - int i=0; - uint16_t col=RGBVAL16(0x00,0x00,0x00); - uint16_t * fb = (uint16_t*)((int)malloc(remaining+64)&0xffffffe0); - while (remaining > 0) { - //uint16_t * fb = blocks[i]; - int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining); -#ifdef TFT_DEBUG - Serial.println((unsigned long)blocks[i]); - Serial.println(remaining); -#endif - switch (i) { - case 0: - //if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb0[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0x00); -#endif - break; - case 1: - //if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb1[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0xff); -#endif - break; - case 2: - //if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb2[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0x00,0xff); -#endif - break; - case 3: - //if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb3[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0xff,0x00,0xff); -#endif - break; - } - blocks[i] = fb; - if (blocks[i] == 0) { - Serial.print("ILI9341 allocaltion failed for block "); - Serial.println(i); - delay(10000); - } - - for (int j=0;jATTR_DST = 1; - dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); - dmasettings[i].interruptAtCompletion(); - fb += len/2; - remaining -= len; - i++; - } - dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); - nbTransfer = i; -#ifdef TFT_DEBUG - Serial.println(nbTransfer); -#endif -} - - -TFT_T_DMA::TFT_T_DMA(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso, uint8_t touch_cs, uint8_t touch_irq) -{ - _cs = cs; - _dc = dc; - _rst = rst; - _mosi = mosi; - _sclk = sclk; - _miso = miso; - pinMode(_dc, OUTPUT); - pinMode(_cs, OUTPUT); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); - if ( (touch_cs != 255) && (touch_irq != 255) ) { - _touch_irq = touch_irq; - _touch_cs = touch_cs; - pinMode(_touch_cs, OUTPUT); - pinMode(touch_irq, INPUT_PULLUP); - digitalWrite(_touch_cs, 1); - } -} - - -void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { - int dx=0; - int dy=0; -#ifdef ST7789 - if (TFT_REALWIDTH == TFT_REALHEIGHT) - { -#ifdef ROTATE_SCREEN - if (!flipped) { - dy += 80; - } -#else - if (flipped) { - dx += 80; - } -#endif - } -#endif - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - SPI.transfer16(x1+dx); - digitalWrite(_dc, 1); - SPI.transfer16(x2+dx); - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - digitalWrite(_dc, 1); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - return; - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - - SPI.transfer16(x1+dx); - SPI.transfer16(x2+dx); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - -void TFT_T_DMA::begin(void) { - SPI.setMOSI(_mosi); - SPI.setMISO(_miso); - SPI.setSCK(_sclk); - SPI.begin(); - - // Initialize display - if (_rst != 0xff) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - const uint8_t *addr = init_commands; - digitalWrite(_cs, 0); -#ifdef ILI9341 - while (1) { - uint8_t count = *addr++; - if (count-- == 0) break; - - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - - while (count-- > 0) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - } - - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(ILI9341_DISPON); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); -#endif -#ifdef ST7789 - uint8_t numCommands, numArgs; - uint16_t ms; - numCommands = *addr++; // Number of commands to follow - while(numCommands--) { // For each command... - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - numArgs = *addr++; // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs > 1) { // For each argument... - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - numArgs--; - } - - if (numArgs) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - if(ms) { - ms = *addr++; // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - digitalWrite(_cs, 1); - SPI.endTransaction(); - delay(ms); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - } - } - digitalWrite(_cs, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - SPI.endTransaction(); - - cancelled = false; - -#ifdef FLIP_SCREEN - flipscreen(true); -#else - flipscreen(false); -#endif -#ifdef ST7789 - if (TFT_REALWIDTH != TFT_REALHEIGHT) - { - flipscreen(true); - } -#endif -}; - - - -void TFT_T_DMA::flipscreen(bool flip) -{ - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(TFT_MADCTL); - digitalWrite(_dc, 1); - if (flip) { - flipped=true; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB); -#endif -#endif - } - else { - flipped=false; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB); -#endif -#endif - } - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - -boolean TFT_T_DMA::isflipped(void) -{ - return(flipped); -} - - -#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) - - -void TFT_T_DMA::startDMA(void) { - curTransfer = 0; - rstop = 0; - //dmatx.begin(true); - dmatx.attachInterrupt(dmaInterrupt); - setDmaStruct(); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - - digitalWrite(_cs, HIGH); - SPI.begin(); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); - - - LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: - LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX - LPSPIP_TCR = 15; // Framesize 16 Bits - //LPSPIP_FCR = 0; // Fifo Watermark - LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable - LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: - dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); - - dmatx = dmasettings[0]; - digitalWrite(_cs, 0); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - dmatx.enable(); -} - - -void TFT_T_DMA::stopDMA(void) { - rstop = 0; - wait(); - delay(50); - cancelled = false; - dmatx.detachInterrupt(); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - SPI.end(); -#ifdef ST7789 - begin(); -#endif -#ifdef ILI9341 - SPI.begin(); - digitalWrite(_cs, 0); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - SPI.endTransaction(); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); -} - -void TFT_T_DMA::wait(void) { - rstop = 1; - unsigned long m = millis(); - cancelled = true; - while (!rstop) { - if ((millis() - m) > 100) break; - delay(10); - asm volatile("wfi"); - }; - rstop = 0; -} - -int TFT_T_DMA::get_frame_buffer_size(int *width, int *height, int *stride){ - if (width != nullptr) *width = TFT_WIDTH; - if (stride != nullptr) *stride = TFT_WIDTH; - if (height != nullptr) *height = TFT_HEIGHT; - return TFT_REALWIDTH; -} - - -/*********************************************************************************************** - Touch functions - ***********************************************************************************************/ -/* Code based on ... - * - * @file XPT2046.cpp - * @date 19.02.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the XPT2046 driver for Arduino. - */ - -#define ADC_MAX 0x0fff - -void TFT_T_DMA::enableTouchIrq() -{ - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 }; - SPI.transfer((void*)&buf[0],3); - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); -} - -//Default callibration for non flipped -#define TX_MIN 30 -#define TY_MIN 20 -#define TX_MAX 300 -#define TY_MAX 220 - -//Default callibration for flipped -#define TFX_MIN 20 -#define TFY_MIN 25 -#define TFX_MAX 288 -#define TFY_MAX 221 - -static uint16_t txMin; -static uint16_t tyMin; -static uint16_t txMax; -static uint16_t tyMax; - - -void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { - if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) { - txMin = xMin; - tyMin = yMin; - txMax = xMax; - tyMax = yMax; - } - else { - if (flipped) { - txMin = TFX_MIN; - tyMin = TFY_MIN; - txMax = TFX_MAX; - tyMax = TFY_MAX; - } - else { - txMin = TX_MIN; - tyMin = TY_MIN; - txMax = TX_MAX; - tyMax = TY_MAX; - } - } -} - - -void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - if ( TOUCH_ENABLED() ) { - uint16_t x = 0; - uint16_t y = 0; - uint16_t z1 = 0; - uint16_t z2 = 0; - uint8_t i = 0; - int16_t xraw=0, yraw=0; - - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - - for(; i < 15; i++) { - // SPI requirer 32bit aliment - uint8_t buf[12] = { - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00 - }; - SPI.transfer(&buf[0], &buf[0], 12); - y += (buf[1] << 8 | buf[2])>>3; - x += (buf[4] << 8 | buf[5])>>3; - z1 += (buf[7] << 8 | buf[8])>>3; - z2 += (buf[10] << 8 | buf[11])>>3; - } - enableTouchIrq(); - - if(i == 0) { - *oX = 0; - *oY = 0; - *oZ = 0; - } - else { - x /= i; - y /= i; - z1 /= i; - z2 /= i; - } - - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); - int z = z1 + ADC_MAX - z2; - if (flipped) { - xraw = x; - yraw = y; - } else { - xraw = ADC_MAX - x; - yraw = ADC_MAX - y; - } - xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1); - yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1); - - *oX = xraw; - *oY = yraw; - *oZ = z; - } - else - { - *oX = 0; - *oY = 0; - *oZ = 0; - } -} - -void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - readRaw(oX,oY,oZ); - // callibrate ... - if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin); - if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin); - //Serial.print(*oX); - //Serial.print(" "); - //Serial.println(*oY); -} - - -/*********************************************************************************************** - No DMA functions - ***********************************************************************************************/ -void TFT_T_DMA::fillScreenNoDma(uint16_t color) { - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - int i,j; - for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(arx, ary, arx+arw-1, ary+arh-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - bits = *charpt++; - //digitalWrite(_dc, 1); - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - x +=8; -#ifdef ILI9341 - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); -#endif - digitalWrite(_cs, 1); - SPI.endTransaction(); - } - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - - - -/*********************************************************************************************** - DMA functions - ***********************************************************************************************/ -uint16_t * TFT_T_DMA::getLineBuffer(int j) -{ - uint16_t * block=blocks[j>>6]; - return(&block[(j&0x3F)*TFT_REALWIDTH]); -} - -void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) { - uint8_t *buffer=buf; - uint8_t *src; - - int i,j,y=0; - if (width*2 <= TFT_REALWIDTH) { - for (j=0; j>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH]; - for (i=0; i>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x]; - for (i=0; i>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - block=blocks[l>>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt++; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - x +=8; - } -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { - drawSprite(x,y,bitmap, 0,0,0,0); -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) -{ - int bmp_offx = 0; - int bmp_offy = 0; - uint16_t *bmp_ptr; - - int w =*bitmap++; - int h = *bitmap++; - - - if ( (arw == 0) || (arh == 0) ) { - // no crop window - arx = x; - ary = y; - arw = w; - arh = h; - } - else { - if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - int l=ary; - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx]; - bmp_ptr = (uint16_t*)bitmap; - for (int col=0;col -#include -#include -#endif - -#include "tft_t_dma_config.h" - -#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) -#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define R16(rgb) ((rgb>>8)&0xf8) -#define G16(rgb) ((rgb>>3)&0xfc) -#define B16(rgb) ((rgb<<3)&0xf8) - -#define PAL_COLOR_MASK 0xff - -#ifdef LOHRES -#define TFT_WIDTH 240 -#define TFT_REALWIDTH 240 -#else -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 -#endif -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - -//#define WIDTH 272 -//#define HEIGHT 228 - -#define LINES_PER_BLOCK 64 -#define NR_OF_BLOCK 4 -#define SCREEN_DMA_NUM_SETTINGS NR_OF_BLOCK - - -#ifdef ILI9341 - -#define ILI9341_NOP 0x00 -#define ILI9341_SWRESET 0x01 -#define ILI9341_RDDID 0x04 -#define ILI9341_RDDST 0x09 - -#define ILI9341_SLPIN 0x10 -#define ILI9341_SLPOUT 0x11 -#define ILI9341_PTLON 0x12 -#define ILI9341_NORON 0x13 - -#define ILI9341_RDMODE 0x0A -#define ILI9341_RDMADCTL 0x0B -#define ILI9341_RDPIXFMT 0x0C -#define ILI9341_RDIMGFMT 0x0D -#define ILI9341_RDSELFDIAG 0x0F - -#define ILI9341_INVOFF 0x20 -#define ILI9341_INVON 0x21 -#define ILI9341_GAMMASET 0x26 -#define ILI9341_DISPOFF 0x28 -#define ILI9341_DISPON 0x29 - -#define ILI9341_CASET 0x2A -#define ILI9341_PASET 0x2B -#define ILI9341_RAMWR 0x2C -#define ILI9341_RAMRD 0x2E - -#define ILI9341_PTLAR 0x30 -#define ILI9341_MADCTL 0x36 -#define ILI9341_VSCRSADD 0x37 -#define ILI9341_PIXFMT 0x3A - -#define ILI9341_FRMCTR1 0xB1 -#define ILI9341_FRMCTR2 0xB2 -#define ILI9341_FRMCTR3 0xB3 -#define ILI9341_INVCTR 0xB4 -#define ILI9341_DFUNCTR 0xB6 - -#define ILI9341_PWCTR1 0xC0 -#define ILI9341_PWCTR2 0xC1 -#define ILI9341_PWCTR3 0xC2 -#define ILI9341_PWCTR4 0xC3 -#define ILI9341_PWCTR5 0xC4 -#define ILI9341_VMCTR1 0xC5 -#define ILI9341_VMCTR2 0xC7 - -#define ILI9341_RDID1 0xDA -#define ILI9341_RDID2 0xDB -#define ILI9341_RDID3 0xDC -#define ILI9341_RDID4 0xDD - -#define ILI9341_GMCTRP1 0xE0 -#define ILI9341_GMCTRN1 0xE1 - -#define ILI9341_MADCTL_MY 0x80 -#define ILI9341_MADCTL_MX 0x40 -#define ILI9341_MADCTL_MV 0x20 -#define ILI9341_MADCTL_ML 0x10 -#define ILI9341_MADCTL_RGB 0x00 -#define ILI9341_MADCTL_BGR 0x08 -#define ILI9341_MADCTL_MH 0x04 - -#define TFT_CASET ILI9341_CASET -#define TFT_PASET ILI9341_PASET -#define TFT_RAMWR ILI9341_RAMWR -#define TFT_MADCTL ILI9341_MADCTL - -#endif - - -#ifdef ST7789 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_RGB 0x00 -#define ST77XX_MADCTL_BGR 0x08 -#define ST77XX_MADCTL_MH 0x04 - -#define TFT_CASET ST7735_CASET -#define TFT_PASET ST7735_RASET -#define TFT_RAMWR ST7735_RAMWR -#define TFT_MADCTL ST7735_MADCTL - -#endif - - - -#ifdef __cplusplus - -class TFT_T_DMA -{ - public: - TFT_T_DMA(uint8_t _CS, uint8_t _DC, uint8_t _RST = 255, uint8_t _MOSI=11, uint8_t _SCLK=13, uint8_t _MISO=12, uint8_t touch_cs=38, uint8_t touch_irq=37); - - void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); - void begin(void); - void flipscreen(bool flip); - boolean isflipped(void); - void startDMA(void); - void stopDMA(); - int get_frame_buffer_size(int *width, int *height, int *stride); - - // Touch screen functions - #define TOUCH_ENABLED() ((_touch_cs != 255) && (_touch_irq != 255)) - bool isTouching(void) { return ((!TOUCH_ENABLED())?false:(digitalRead(_touch_irq) == LOW)); } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax); - - // NoDMA functions - void writeScreenNoDma(const uint16_t *pcolors); - void fillScreenNoDma(uint16_t color); - void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - // DMA functions - uint16_t * getLineBuffer(int j); - void writeScreen(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int y, uint16_t *buf); - void fillScreen(uint16_t color); - void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - protected: - uint8_t _rst, _cs, _dc; - uint8_t _miso, _mosi, _sclk; - uint8_t _touch_irq=255, _touch_cs=255; - bool flipped=false; - - void wait(void); - void enableTouchIrq(); -}; - -#endif -#endif diff --git a/MCUME_teensy41/teensyhandy/tft_t_dma_config.h b/MCUME_teensy41/teensyhandy/tft_t_dma_config.h deleted file mode 100644 index 354cf74..0000000 --- a/MCUME_teensy41/teensyhandy/tft_t_dma_config.h +++ /dev/null @@ -1,14 +0,0 @@ -#include "platform_config.h" - -//#define ST7789 1 -//#define ILI9341 1 - -#define TFT_LINEARINT 1 -#define LINEARINT_HACK 1 - -//#define FLIP_SCREEN 1 -//#define TFT_DEBUG 1 -#if defined(__IMXRT1052__) || defined(__IMXRT1062__) -//#define TFT_STATICFB 1 -#endif - diff --git a/MCUME_teensy41/teensyhandy/vga_t_dma.h b/MCUME_teensy41/teensyhandy/vga_t_dma.h deleted file mode 100644 index 81a986b..0000000 --- a/MCUME_teensy41/teensyhandy/vga_t_dma.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - Wrapping class to extend VGA_T4 to TFT_T_DMA -*/ - -#ifndef _VGA_T_DMAH_ -#define _VGA_T_DMAH_ - -#ifdef __cplusplus -#include -#endif - - -#define RGBVAL16(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) - - - - -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 - -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - - - -#ifdef __cplusplus - -class TFT_T_DMA: public VGA_T4 -{ - public: - // Fake touch screen functions - bool isTouching(void) { return false; } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { } - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { }; - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { } - - // fake DMA functions - void startDMA(void) { }; - void stopDMA(void) { }; - - // fake no DMA functions - void writeScreenNoDma(const vga_pixel *pcolors) { writeScreen(pcolors); } - void fillScreenNoDma(vga_pixel color) { clear(color); } - void drawTextNoDma(int16_t x, int16_t y, const char * text, vga_pixel fgcolor, vga_pixel bgcolor, bool doublesize) { drawText(x,y,text,fgcolor,bgcolor,doublesize); } - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, vga_pixel color) { drawRect(x, y, w, h, color); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap) { drawSprite(x, y, bitmap); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh) { drawSprite(x, y, bitmap, croparx, cropary, croparw, croparh); } -}; - - -#endif -#endif diff --git a/MCUME_teensy41/teensyhandy/lynx.cpp b/MCUME_teensy41/teensyhandy/wrapemu.cpp similarity index 90% rename from MCUME_teensy41/teensyhandy/lynx.cpp rename to MCUME_teensy41/teensyhandy/wrapemu.cpp index bb88263..0e22eee 100644 --- a/MCUME_teensy41/teensyhandy/lynx.cpp +++ b/MCUME_teensy41/teensyhandy/wrapemu.cpp @@ -43,7 +43,6 @@ static int dpad_mapped_up; static int dpad_mapped_down; static int dpad_mapped_left; static int dpad_mapped_right; -static int width, height; #define DISPLAY_ROTATION_OFF 0 #define DISPLAY_ROTATION_LEFT 1 @@ -82,9 +81,6 @@ void emu_KeyboardOnUp(int keymodifer, int key) { void lnx_Init(void) { -#ifdef HAS_SND - emu_sndInit(); -#endif } @@ -92,9 +88,6 @@ void lnx_Start(char * filename) { emu_printf("emu starting"); -#ifdef HAS_SND -#endif - lynx = new CSystem(filename, MIKIE_PIXEL_FORMAT_16BPP_565, HANDY_AUDIO_SAMPLE_FREQ); if (lynx->mFileType == HANDY_FILETYPE_ILLEGAL) { @@ -102,7 +95,9 @@ void lnx_Start(char * filename) return; } - gPrimaryFrameBuffer = (UBYTE*)((HandyPixel*)emu_LineBuffer(0)+1 ); +// gPrimaryFrameBuffer = (UBYTE*)(emu_SMalloc((HANDY_SCREEN_HEIGHT+1)*HANDY_SCREEN_STRIDE*sizeof(HandyPixel))); + gPrimaryFrameBuffer = (UBYTE*)(emu_SMalloc((OUTPUT_SCREEN_HEIGHT)*OUTPUT_SCREEN_WIDTH*sizeof(HandyPixel))); + memset((void *)gPrimaryFrameBuffer, 0,(OUTPUT_SCREEN_HEIGHT)*OUTPUT_SCREEN_WIDTH*sizeof(HandyPixel)); gAudioBuffer = &sndbuffer[0]; memset(&sndbuffer[0], AUDIO_BUFFER_LENGTH*4,0); gAudioEnabled = 1; @@ -137,8 +132,6 @@ void lnx_Start(char * filename) switch(rotation) { case DISPLAY_ROTATION_LEFT: - width = HANDY_SCREEN_HEIGHT; - height = HANDY_SCREEN_WIDTH; lynx->mMikie->SetRotation(MIKIE_ROTATE_L); dpad_mapped_up = BUTTON_RIGHT; dpad_mapped_down = BUTTON_LEFT; @@ -146,8 +139,6 @@ void lnx_Start(char * filename) dpad_mapped_right = BUTTON_DOWN; break; case DISPLAY_ROTATION_RIGHT: - width = HANDY_SCREEN_HEIGHT; - height = HANDY_SCREEN_WIDTH; lynx->mMikie->SetRotation(MIKIE_ROTATE_R); dpad_mapped_up = BUTTON_LEFT; dpad_mapped_down = BUTTON_RIGHT; @@ -155,8 +146,6 @@ void lnx_Start(char * filename) dpad_mapped_right = BUTTON_UP; break; default: - width = HANDY_SCREEN_WIDTH; - height = HANDY_SCREEN_HEIGHT; lynx->mMikie->SetRotation(MIKIE_NO_ROTATE); dpad_mapped_up = BUTTON_UP; dpad_mapped_down = BUTTON_DOWN; @@ -177,6 +166,12 @@ void lnx_Step(void) #ifdef TEECOMPUTER int hk = ihk; if (hk == 'q') { + buttons |= BUTTON_OPT1; + } + if (hk == 'w') { + buttons |= BUTTON_OPT2; + } + if (hk == 'e') { buttons |= BUTTON_PAUSE; } #endif @@ -185,14 +180,19 @@ void lnx_Step(void) if ( (k & MASK_JOY2_LEFT) || (k & MASK_JOY1_LEFT) ) buttons |= dpad_mapped_left; if ( (k & MASK_JOY2_RIGHT) || (k & MASK_JOY1_RIGHT) ) buttons |= dpad_mapped_right; if ( (k & MASK_JOY2_BTN) || (k & MASK_JOY1_BTN) ) buttons |= BUTTON_A; - if ( (k & MASK_KEY_USER1) ) buttons |= BUTTON_B; - if ( (k & MASK_KEY_USER2) ) buttons |= BUTTON_OPT2; + if ( (k & MASK_KEY_USER1) ) buttons |= BUTTON_A; + if ( (k & MASK_KEY_USER2) ) buttons |= BUTTON_B; if ( (k & MASK_KEY_USER3) ) buttons |= BUTTON_OPT1; lynx->SetButtonData(buttons); lynx->UpdateFrame(true); + HandyPixel * buf = (HandyPixel *)gPrimaryFrameBuffer; + for (int j=0; j -#ifdef HAS_USBKEY +#ifdef HAS_USB #include "USBHost_t36.h" // Read this header first for key info USBHost myusb; USBHub hub1(myusb); +#ifdef HAS_USBKEY KeyboardController keyboard1(myusb); USBHIDParser hid1(myusb); MouseController mouse1(myusb); +#endif +#ifdef HAS_USBMIDI MIDIDevice midi1(myusb); #endif +#ifdef HAS_USBJOY +#define COUNT_JOYSTICKS 4 +JoystickController joysticks[COUNT_JOYSTICKS](myusb); +#endif +#endif static bool emu_writeConfig(void); static bool emu_readConfig(void); static bool emu_eraseConfig(void); +static bool emu_writeGfxConfig(char * display_type); +static int emu_readGfxConfig(void); static bool mouseDetected = false; static bool keyboardDetected = false; @@ -34,12 +40,13 @@ static File file; #define MAX_FILES 64 #define AUTORUN_FILENAME "autorun.txt" +#define GFX_CFG_FILENAME "gfxmode.txt" -#define MAX_FILENAME_SIZE 24 +#define MAX_FILENAME_SIZE 34 #define MAX_MENULINES 9 #define TEXT_HEIGHT 16 #define TEXT_WIDTH 8 -#define MENU_FILE_XOFFSET (6*TEXT_WIDTH) +#define MENU_FILE_XOFFSET (2*TEXT_WIDTH) #define MENU_FILE_YOFFSET (2*TEXT_HEIGHT) #define MENU_FILE_W (MAX_FILENAME_SIZE*TEXT_WIDTH) #define MENU_FILE_H (MAX_MENULINES*TEXT_HEIGHT) @@ -53,7 +60,8 @@ static File file; #define MENU_VGA_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) #define MENU_VGA_YOFFSET (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37) -extern TFT_T_DMA tft; +#include "t4_dsp.h" +T4_DSP tft; static int nbFiles=0; static int curFile=0; @@ -65,6 +73,8 @@ static char selected_filename[MAX_FILENAME_SIZE]=""; static char second_selected_filename[MAX_FILENAME_SIZE]=""; static bool menuRedraw=true; static bool autorun=false; +static bool vgahires=false; + static const unsigned short * keys; #ifdef TEECOMPUTER @@ -158,6 +168,29 @@ void emu_Free(void * pt) free(pt); } +#define SMEMPOOL (0x800000) +EXTMEM static unsigned char slowmem[SMEMPOOL]; +static int slowmempt = 0; + +void * emu_SMalloc(unsigned int size) +{ + void * mem = (void*)&slowmem[slowmempt]; + slowmempt += size; + + if ( slowmempt > SMEMPOOL ) { + mem = NULL; + emu_printf("failure to allocate slow"); + } + else { + emu_printf("could allocate slow static "); + emu_printf(size); + } + return mem; +} + +void emu_SFree(void * pt) +{ +} /******************************** * Input and keyboard ********************************/ @@ -329,6 +362,12 @@ int emu_ReadKeys(void) #endif if ( row & 0x02 ) retval |= MASK_JOY2_BTN; + +#ifdef EXTPAD + if ( sh_pressed ) retval |= MASK_KEY_USER3; + if ( fn_pressed ) retval |= MASK_KEY_USER1; + digitalWrite(KLED, 0); +#else // Handle LED flash uint32_t time_ms=millis(); if ((time_ms-last_t_ms) > 100) { @@ -412,8 +451,9 @@ int emu_ReadKeys(void) if ( key_fn ) retval |= MASK_KEY_USER2; if ( ( key_fn ) && (keymatrix[4] == 0x10 )) retval |= MASK_KEY_USER1; +#endif - if ( (key_fn) && (key_sh) ) + if ( (fn_pressed) && (sh_pressed) ) #else if ( ((retval & (MASK_KEY_USER1+MASK_KEY_USER2)) == (MASK_KEY_USER1+MASK_KEY_USER2)) || (retval & MASK_KEY_USER4 ) ) @@ -453,8 +493,10 @@ int emu_ReadKeys(void) while (true) { ; } -#endif +#endif } + + emu_GetJoystick(); return (retval); } @@ -607,7 +649,7 @@ int emu_setKeymap(int index) { } int emu_GetMouse(int *x, int *y, int *buts) { -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBKEY) if (mouse1.available()) { *buts = mouse1.getButtons(); *x = mouse1.getMouseX(); @@ -620,7 +662,23 @@ int emu_GetMouse(int *x, int *y, int *buts) { return 0; } -#ifdef HAS_USBKEY +int emu_GetJoystick(void) { +#if defined(HAS_USB) && (HAS_USBJOY) + for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) { + if (joysticks[joystick_index].available()) { + uint64_t axis_mask = joysticks[joystick_index].axisMask(); + uint64_t axis_changed_mask = joysticks[joystick_index].axisChangedMask(); + uint32_t buttons = joysticks[joystick_index].getButtons(); + Serial.printf("Joystick(%d): buttons = %x", joystick_index, buttons); + Serial.println(); + } + } + return 1; +#endif + return 0; +} + +#if defined(HAS_USB) && (HAS_USBKEY) void OnPress(auto key) { keyboardDetected = true; @@ -764,7 +822,7 @@ int emu_KeyboardDetected(void) { return (keyboardDetected?1:0); } -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) static unsigned char midiBuffer[16]; static unsigned char midiLastCmd=0; static int midiDataCnt=0; @@ -772,8 +830,7 @@ static int midiCmdNbParam=0; #endif void emu_MidiOnDataReceived(unsigned char value) { - -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) //Serial.println(value, HEX); //10000000 = 128 = note off //10010000 = 144 = note on @@ -941,6 +998,7 @@ void emu_MidiOnDataReceived(unsigned char value) { /******************************** * Menu file loader UI ********************************/ +#ifdef FILEBROWSER static int readNbFiles(void) { int totalFiles = 0; @@ -970,8 +1028,6 @@ static int readNbFiles(void) { return totalFiles; } - - void backgroundMenu(void) { menuRedraw=true; tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00)); @@ -981,11 +1037,13 @@ void backgroundMenu(void) { int handleMenu(uint16_t bClick) { if (autorun) { + toggleMenu(false); + menuRedraw=false; return (ACTION_RUN1); } int action = ACTION_NONE; - if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) ) { + if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) || ( bClick & MASK_KEY_USER2 ) ) { char newpath[MAX_FILENAME_PATH]; strcpy(newpath, selection); strcat(newpath, "/"); @@ -996,17 +1054,31 @@ int handleMenu(uint16_t bClick) File file = SD.open(selection); if (file.isDirectory()) { curFile = 0; - nbFiles = readNbFiles(); + nbFiles = readNbFiles(); + menuRedraw=true; } - else { - action = ACTION_RUN1; + else + { #ifdef TEECOMPUTER - if (key_extmode) { + if ( (key_extmode) || ( key_sh) ) { emu_writeConfig(); } + if ( tft.getMode() < MODE_VGA_320x240) { + if ( bClick & MASK_KEY_USER2 ) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + } + //emu_SwapJoysticks(0); #endif + toggleMenu(false); + menuRedraw=false; + return (ACTION_RUN1); } - menuRedraw=true; } else if ( bClick & MASK_KEY_USER1 ) { menuRedraw=true; @@ -1015,19 +1087,14 @@ int handleMenu(uint16_t bClick) strcat(second_selection, "/"); strcat(second_selection, second_selected_filename); action = ACTION_RUN2; - } - else if ( bClick & MASK_KEY_USER2 ) { - menuRedraw=true; - //action = ACTION_RUN3; - emu_SwapJoysticks(0); - } + } else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) { if (curFile!=0) { menuRedraw=true; curFile--; } } - else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { + else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { if ((curFile-9)>=0) { menuRedraw=true; curFile -= 9; @@ -1042,7 +1109,7 @@ int handleMenu(uint16_t bClick) menuRedraw=true; } } - else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { + else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { if ((curFile<(nbFiles-9)) && (nbFiles)) { curFile += 9; menuRedraw=true; @@ -1099,12 +1166,12 @@ int handleMenu(uint16_t bClick) return (action); } -bool menuActive(void) +int menuActive(void) { - return (menuOn); + return (menuOn?1:0); } -void toggleMenu(bool on) { +void toggleMenu(int on) { if (on) { menuOn=true; backgroundMenu(); @@ -1122,7 +1189,7 @@ char * menuSecondSelection(void) { return (second_selection); } - +#endif /******************************** * OSKB handling @@ -1140,8 +1207,9 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) char c[4] = {' ',0,' ',0}; const char * cpt = str; int i=0; - int fb_width,fb_height; - tft.get_frame_buffer_size(&fb_width, &fb_height); + int fb_width,fb_height,fbstride; + + fbstride = tft.get_frame_buffer_size(&fb_width, &fb_height); int ypos = (bottom?(fb_height-2*8):0); int line = row + (bottom?2:0); while ((c[1] = *cpt++)) @@ -1150,7 +1218,7 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0); else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff); if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff); - tft.drawTextNoDma(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); + tft.drawText(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); i++; } } @@ -1248,7 +1316,7 @@ int handleOSKB(void) { return retval; } -void toggleOSKB(bool forceon) { +void toggleOSKB(int forceon) { if (forceon) { oskbOn = true; drawOSKB(); @@ -1332,6 +1400,17 @@ int emu_FileRead(void * buf, int size, int handler) #endif } +int emu_FileWrite(void * buf, int size, int handler) +{ +// emu_printf("emu_FileWrite"); +// emu_printi(handler); +#ifdef HCFH + return (file.write(buf, size)); +#else + return (getFileHandler(handler).write(buf, size)); +#endif +} + int emu_FileGetc(int handler) { // emu_printf("FileGetc"); // emu_printi(handler); @@ -1404,6 +1483,9 @@ unsigned int emu_FileSize(const char * filepath) emu_printf(filesize); lofile.close(); } + else { + emu_printf("filesize failed"); + } return(filesize); } @@ -1489,6 +1571,48 @@ static bool emu_eraseConfig(void) SD.remove (ROMSDIR "/" AUTORUN_FILENAME); } +static bool emu_writeGfxConfig(char * display_type) +{ + bool retval = false; + SD.remove ("/" GFX_CFG_FILENAME); + if (strcmp(display_type, "VGA")) { + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(display_type, strlen(display_type)) != strlen(display_type)) { + emu_printf("GFX config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + } + return retval; +} + +#define CFG_VGA 0 +#define CFG_ILI 1 +#define CFG_ST 2 + +static int emu_readGfxConfig(void) +{ + int retval = CFG_VGA; // No file = VGA + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + if (filesize == 2) // "ST" + { + retval = CFG_ST; + } + else if (filesize == 3) // "ILI" + { + retval = CFG_ILI; + } + lofile.close(); + } + return retval; +} + /******************************** * File IO compatibility ********************************/ @@ -1670,62 +1794,249 @@ FRESULT f_mkdir (const char* path) /******************************** - * Initialization + * GFX wrapper ********************************/ -void emu_init(void) +static unsigned short palette16[PALETTE_SIZE]; +static IntervalTimer myTimer; +volatile boolean vbl=true; +volatile boolean vgatimervsync=false; +static void (*vblCallback)(void) = nullptr; +static int skip=0; + +static void vblCount() { + if (vbl) { + vbl = false; + } else { + vbl = true; + } +} + +void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) +{ + if (index= MODE_VGA_320x240 ) { + if (vgatimervsync) { + while (vbl==vb) {}; + } + else { + tft.waitSync(); + } + } + else { + while (vbl==vb) {}; + } + if (vblCallback != nullptr) { + vblCallback(); + } +} + +void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride) +{ + if (skip == 0) { + tft.writeScreenPal(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); + } +} +void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLinePal(width,height,line, VBuf, palette16); + } +} + +void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine(width,height,line, VBuf); + } +} + +void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine8(width,height,line, VBuf, palette16); + } +} + +int emu_IsVga(void) +{ + return (tft.getMode() >= MODE_VGA_320x240?1:0); +} + +int emu_IsVgaHires(void) +{ + return (tft.getMode() >= MODE_VGA_640x240?1:0); +} + +int emu_FrameSkip(void) +{ + return skip; +} + + +/******************************** + * AUDIO wrapper +********************************/ +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +AudioPlaySystem mymixer; + +void emu_sndInit() { + Serial.println("sound init"); + mymixer.begin_audio(256, mymixer.snd_Mixer); + mymixer.start(); +} + +void emu_sndPlaySound(int chan, int volume, int freq) +{ + if (chan < 6) { + mymixer.sound(chan, freq, volume); + } + /* + Serial.print(chan); + Serial.print(":" ); + Serial.print(volume); + Serial.print(":" ); + Serial.println(freq); + */ +} + +void emu_sndPlayBuzz(int size, int val) { + mymixer.buzz(size,val); + //Serial.print((val==1)?1:0); + //Serial.print(":"); + //Serial.println(size); +} +#endif + +/******************************** + * Initialization +********************************/ +void emu_init(int hires) { Serial.begin(115200); + vgahires = hires; -#ifdef HAS_USBKEY +#ifdef HAS_USB myusb.begin(); +#ifdef HAS_USBKEY keyboard1.attachPress(OnPress); keyboard1.attachRelease(OnRelease); #endif +#endif - while (!SD.begin(SD_CS)) +#ifdef FILEBROWSER + if (!SD.begin(SD_CS)) { - Serial.println("SD begin failed, retrying..."); - delay(1000); + Serial.println("No SD card detected"); } strcpy(selection,ROMSDIR); - FileHandlersInit(); - nbFiles = readNbFiles(); - - Serial.print("SD initialized, files found: "); Serial.println(nbFiles); +#endif emu_InitJoysticks(); #ifdef SWAP_JOYSTICK - joySwapped = true; + joySwapped = true; #else - joySwapped = false; + joySwapped = false; #endif -#ifdef TEECOMPUTER -#ifndef HAS_T4_VGA - tft.flipscreen(false); -#endif -#endif int keypressed = emu_ReadKeys(); +#ifdef HAS_T4_VGA + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } +#else + int gfx_mode = CFG_VGA; // default +#ifdef FILEBROWSER + gfx_mode = emu_readGfxConfig(); +#endif + // Force VGA if UP pressed + if (keypressed & MASK_JOY2_UP) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("VGA"); +#endif + gfx_mode = CFG_VGA; + } + else { + if (keypressed & MASK_JOY2_LEFT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ST"); +#endif + gfx_mode = CFG_ST; + } + else if (keypressed & MASK_JOY2_RIGHT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ILI"); +#endif + gfx_mode = CFG_ILI; + } + } + if (gfx_mode == CFG_VGA) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + else + { + tft.begin(gfx_mode == CFG_ILI?MODE_TFTILI_320x240:MODE_TFTST_320x240); + } +#endif + if (keypressed & MASK_JOY2_DOWN) { tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) ); tft.drawTextNoDma(64,48, (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); +#ifdef FILEBROWSER emu_eraseConfig(); delay(1000); +#endif } else { +#ifdef FILEBROWSER if (emu_readConfig()) { autorun = true; } +#endif } +#ifdef FILEBROWSER toggleMenu(true); +#endif } -void emu_start(void) +void emu_start(int vblms, void * callback, int forcetimervsync) { + vgatimervsync = forcetimervsync?true:false; + tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); + tft.startRefresh(); + if (callback != nullptr) { + vblCallback = callback; + } + + myTimer.begin(vblCount, vblms); +#ifdef HAS_SND + emu_sndInit(); +#endif usbnavpad = 0; } diff --git a/MCUME_teensy41/teensylogo/emuapi.h b/MCUME_teensy41/teensylogo/emuapi.h index a9a32d7..5dd6130 100644 --- a/MCUME_teensy41/teensylogo/emuapi.h +++ b/MCUME_teensy41/teensylogo/emuapi.h @@ -2,126 +2,14 @@ #define EMUAPI_H #include "platform_config.h" - -#define CUSTOM_SND 1 -//#define TIMER_REND 1 - -#define EXTRA_HEAP 0x10 - -// Title: < > -#define TITLE " Demo MCUME " -#define ROMSDIR "/c64" - -#define emu_Init(ROM1,ROM2) {uae_Start(ROM1,ROM2);} -#define emu_Init2() {uae_Init();} -#define emu_Step(x) {uae_Step();} -#define emu_Input(x) {uae_Input(x);} - -#define MAX_FILENAME_PATH 64 -#define NB_FILE_HANDLER 4 -#define PALETTE_SIZE 1 -#define VID_FRAME_SKIP 0x0 -#define TFT_VBUFFER_YCROP 0 -#define SINGLELINE_RENDERING 1 - -#define R32(rgb) ((rgb>>16)&0xff) -#define G32(rgb) ((rgb>>8)&0xff) -#define B32(rgb) (rgb & 0xff) +#include "emucfg.h" #define ACTION_NONE 0 -#define ACTION_MAXKBDVAL 16 -#define ACTION_EXITKBD 128 -#define ACTION_RUN1 129 -#define ACTION_RUN2 130 -#define ACTION_RUN3 131 - - -#ifdef KEYMAP_PRESENT - -#define keylables_map0_0 (char *)"qwertyuiop\x1a" -#define keylables_map0_1 (char *)" asdfghjkl\x19" -#define keylables_map0_2 (char *)" zxcvbnm,.;/" -#define keylables_map0_3 (char *)" +\x10-" -const unsigned short key_map0[] = { - 'q','w','e','r','t','y','u','i','o','p',157, //lowecase - 0,'a','s','d','f','g','h','j','k','l',0x0D, - 0,'z','x','c','v','b','n','m',',','.',';','/', - 145,157,29,17, - 0,'+',' ','-' - }; - -#define keylables_map1_0 (char *)"QWERTYUIOP@" -#define keylables_map1_1 (char *)" ASDFGHJKL\x19" -#define keylables_map1_2 (char *)" ZXCVBNM<>:?" -#define keylables_map1_3 (char *)" =\x10_" -const unsigned short key_map1[] = { - 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase - 0,'A','S','D','F','G','H','J','K','L',0x0D, - 0,'Z','X','C','V','B','N','M','<','>',':','?', - 145,157,29,17, - 0,'=',' ','_' - }; - -#define keylables_map2_0 (char *)"!\"#$%^&*()@" -#define keylables_map2_1 (char *)" |\\[]{} " -#define keylables_map2_2 (char *)" <>:?" -#define keylables_map2_3 (char *)" =\x10_" -const unsigned short key_map2[] = { - '!','"','#','$','%','^','&','*','(',')','@', // shiftothers - 0, '|','\\','[',']','{','}','\'',0,0,0, - 0, 0,0,0,0,0,0,0,'<','>',':','?', - 0,0,0,0, - 0,'=',' ','_' - }; - -#define keylables_map3_0 (char *)"1234567890 " -#define keylables_map3_1 (char *)" " -#define keylables_map3_2 (char *)" " -#define keylables_map3_3 (char *)" " - -const unsigned short key_map3[] = { - '1','2','3','4','5','6','7','8','9','0',0, // digit keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map4_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " -#define keylables_map4_1 (char *)" " -#define keylables_map4_2 (char *)" " -#define keylables_map4_3 (char *)" " - -const unsigned short key_map4[] = { - 133,134,135,136,137,138,139,140,0,0,0, // function keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map5_0 (char *)" " -#define keylables_map5_1 (char *)" " -#define keylables_map5_2 (char *)" " -#define keylables_map5_3 (char *)" " - -const unsigned short key_map5[] = { - 0,0,0,0,0,0,0,0,0,0,0, // extra keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -const unsigned short matkeys[] = { - 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 - 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 - 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 - 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN - 0x510,0x010,0x110,0x310, // row 4 - }; -#endif +#define ACTION_RUN1 1 +#define ACTION_RUN2 2 +#define FORCE_VGATIMERVSYNC 1 +#define SUPPORT_HIRES 1 #define MASK_JOY2_RIGHT 0x0001 #define MASK_JOY2_LEFT 0x0002 @@ -138,22 +26,25 @@ const unsigned short matkeys[] = { #define MASK_JOY1_BTN 0x1000 #define MASK_KEY_USER4 0x2000 +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) #ifdef __cplusplus extern "C" { +extern void emu_init(int hires=0); +extern void emu_start(int vblms, void * callback, int forcetimervsync=0); #endif - -extern void emu_init(void); -extern void emu_start(void); extern void emu_printf(const char * text); extern void emu_printi(int val); extern void emu_printh(int val); extern void * emu_Malloc(unsigned int size); extern void * emu_MallocI(unsigned int size); extern void emu_Free(void * pt); +extern void * emu_SMalloc(unsigned int size); +extern void emu_SFree(void * pt); extern int emu_FileOpen(const char * filepath, const char * mode); extern int emu_FileRead(void * buf, int size, int handler); +extern int emu_FileWrite(void * buf, int size, int handler); extern int emu_FileGetc(int handler); extern int emu_FileSeek(int handler, int seek, int origin); extern int emu_FileTell(int handler); @@ -164,24 +55,23 @@ extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size); extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek); extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index); -extern void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride); -extern void emu_DrawLine(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line); extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line); +extern void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride); extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line); -extern void emu_CopyLine(int width, int height, int ysrc, int ydst); extern void emu_DrawVsync(void); extern int emu_FrameSkip(void); -extern void * emu_LineBuffer(int line); -extern void emu_tweakVideo(int shiftdelta, int numdelta, int denomdelta); +extern int emu_IsVga(void); +extern int emu_IsVgaHires(void); -extern bool menuActive(void); +extern int menuActive(void); extern char * menuSelection(void); extern char * menuSecondSelection(void); -extern void toggleMenu(bool on); +extern void toggleMenu(int on); extern int handleMenu(unsigned short bClick); extern int handleOSKB(void); -extern void toggleOSKB(bool forceon); +extern void toggleOSKB(int forceon); extern void emu_InitJoysticks(void); extern int emu_SwapJoysticks(int statusOnly); @@ -190,6 +80,7 @@ extern int emu_ReadKeys(void); extern int emu_GetPad(void); extern int emu_GetMouse(int *x, int *y, int *buts); extern int emu_MouseDetected(void); +extern int emu_GetJoystick(void); extern int emu_KeyboardDetected(void); extern int emu_ReadAnalogJoyX(int min, int max); extern int emu_ReadAnalogJoyY(int min, int max); @@ -211,5 +102,4 @@ extern int emu_setKeymap(int index); } #endif - #endif diff --git a/MCUME_teensy41/teensylogo/emucfg.h b/MCUME_teensy41/teensylogo/emucfg.h new file mode 100644 index 0000000..92f55f9 --- /dev/null +++ b/MCUME_teensy41/teensylogo/emucfg.h @@ -0,0 +1,114 @@ +#ifndef EMUCFG_H +#define EMUCFG_H + + +// Title: < > +#define TITLE " Demo MCUME " +#define ROMSDIR "/c64" + +#define emu_Init(x) {} +#define emu_Step(x) {} +#define emu_Input(x) {} + +#define MAX_FILENAME_PATH 64 +#define NB_FILE_HANDLER 4 + +#define PALETTE_SIZE 1 +#define VID_FRAME_SKIP 0x0 +#define TFT_VBUFFER_YCROP 0 +#define SINGLELINE_RENDERING 1 +#define CUSTOM_SND 1 +//#define TIMER_REND 1 +//#define EXTPAD 1 +#define EXTRA_HEAP 0x10 +#define FILEBROWSER 1 + + +#ifdef KEYMAP_PRESENT + +#define keylables_map0_0 (char *)"qwertyuiop\x1a" +#define keylables_map0_1 (char *)" asdfghjkl\x19" +#define keylables_map0_2 (char *)" zxcvbnm,.;/" +#define keylables_map0_3 (char *)" +\x10-" +const unsigned short key_map0[] = { + 'q','w','e','r','t','y','u','i','o','p',157, //lowecase + 0,'a','s','d','f','g','h','j','k','l',0x0D, + 0,'z','x','c','v','b','n','m',',','.',';','/', + 145,157,29,17, + 0,'+',' ','-' + }; + +#define keylables_map1_0 (char *)"QWERTYUIOP@" +#define keylables_map1_1 (char *)" ASDFGHJKL\x19" +#define keylables_map1_2 (char *)" ZXCVBNM<>:?" +#define keylables_map1_3 (char *)" =\x10_" +const unsigned short key_map1[] = { + 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase + 0,'A','S','D','F','G','H','J','K','L',0x0D, + 0,'Z','X','C','V','B','N','M','<','>',':','?', + 145,157,29,17, + 0,'=',' ','_' + }; + +#define keylables_map2_0 (char *)"!\"#$%^&*()@" +#define keylables_map2_1 (char *)" |\\[]{} " +#define keylables_map2_2 (char *)" <>:?" +#define keylables_map2_3 (char *)" =\x10_" +const unsigned short key_map2[] = { + '!','"','#','$','%','^','&','*','(',')','@', // shiftothers + 0, '|','\\','[',']','{','}','\'',0,0,0, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 0,0,0,0, + 0,'=',' ','_' + }; + +#define keylables_map3_0 (char *)"1234567890 " +#define keylables_map3_1 (char *)" " +#define keylables_map3_2 (char *)" " +#define keylables_map3_3 (char *)" " + +const unsigned short key_map3[] = { + '1','2','3','4','5','6','7','8','9','0',0, // digit keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map4_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " +#define keylables_map4_1 (char *)" " +#define keylables_map4_2 (char *)" " +#define keylables_map4_3 (char *)" " + +const unsigned short key_map4[] = { + 133,134,135,136,137,138,139,140,0,0,0, // function keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map5_0 (char *)" " +#define keylables_map5_1 (char *)" " +#define keylables_map5_2 (char *)" " +#define keylables_map5_3 (char *)" " + +const unsigned short key_map5[] = { + 0,0,0,0,0,0,0,0,0,0,0, // extra keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +const unsigned short matkeys[] = { + 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 + 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 + 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 + 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN + 0x510,0x010,0x110,0x310, // row 4 + }; + +#endif + +#endif diff --git a/MCUME_teensy41/teensylogo/platform_config.h b/MCUME_teensy41/teensylogo/platform_config.h index 7a3703a..26bc2da 100644 --- a/MCUME_teensy41/teensylogo/platform_config.h +++ b/MCUME_teensy41/teensylogo/platform_config.h @@ -4,24 +4,24 @@ #define TEECOMPUTER 1 #ifdef TEECOMPUTER - -//#define ILI9341 1 -//#define ST7789 1 -//#define TFTSPI1 1 -#define HAS_T4_VGA 1 -//#define HIRES 1 +#define TFTSPI1 1 +//#define HAS_T4_VGA 1 //#define HAS_SND 1 //#define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 #define PT8211 1 #else #define HAS_T4_VGA 1 -//#define HIRES 1 //#define INVX 1 #define INVY 1 //#define HAS_SND 1 //#define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 +#define PT8211 1 #endif diff --git a/MCUME_teensy41/teensylogo/t4_dsp.cpp b/MCUME_teensy41/teensylogo/t4_dsp.cpp new file mode 100644 index 0000000..43301fa --- /dev/null +++ b/MCUME_teensy41/teensylogo/t4_dsp.cpp @@ -0,0 +1,1774 @@ +/* + TFT/VGA driver + DMA TFT driver based on C64 ILI9341 dma driver from Frank Bösing, 2017 +*/ + +#include "T4_DSP.h" + +#include +#include + +#include "font8x8.h" + +// TFT constants and variables +#define TFT_LINEARINT 1 +#define LINEARINT_HACK 1 +#define DMA_LINES_PER_BLOCK 64 +#define DMA_NUM_SETTINGS 4 + +#define TFT_SWRESET 0x01 +#define TFT_SLPOUT 0x11 +#define TFT_INVON 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_MADCTL 0x36 +#define TFT_PIXFMT 0x3A +#define TFT_MADCTL_MY 0x80 +#define TFT_MADCTL_MX 0x40 +#define TFT_MADCTL_MV 0x20 +#define TFT_MADCTL_ML 0x10 +#define TFT_MADCTL_RGB 0x00 +#define TFT_MADCTL_BGR 0x08 +#define TFT_MADCTL_MH 0x04 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) +//#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) +//#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) +//#define R16(rgb) ((rgb>>8)&0xf8) +//#define G16(rgb) ((rgb>>3)&0xfc) +//#define B16(rgb) ((rgb<<3)&0xf8) + +// LPSPI4 = SPI0 in Teensy 4.0 +// LPSPI3 = SPI1 in Teensy 4.0 +// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) + +#ifdef TFTSPI1 +#define SPI SPI1 +#define LPSPIP_TDR LPSPI3_TDR +#define LPSPIP_CR LPSPI3_CR +#define LPSPIP_CFGR1 LPSPI3_CFGR1 +#define LPSPIP_TCR LPSPI3_TCR +#define LPSPIP_DER LPSPI3_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX +#else +#define LPSPIP_TDR LPSPI4_TDR +#define LPSPIP_CR LPSPI4_CR +#define LPSPIP_CFGR1 LPSPI4_CFGR1 +#define LPSPIP_TCR LPSPI4_TCR +#define LPSPIP_DER LPSPI4_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX +#endif + +#define SPICLOCK 60000000 +#define SPI_MODE SPI_MODE0 + +// VGA constants and macros +typedef uint8_t vga_pixel; +#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) + +static DMASetting dmasettings[DMA_NUM_SETTINGS]; +static DMAChannel dmatx; +static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K +static volatile uint8_t rstop = 0; +static volatile bool cancelled = false; +static volatile uint8_t curTransfer = 0; +static uint8_t nbTransfer = 0; +static uint16_t * tft_buffer; +static int tft_width; +static int tft_height; +static int tft_stride; + +#define DELAY_MASK 0x80 +PROGMEM static const uint8_t init_commands[] = { + 1+DELAY_MASK, TFT_SWRESET, 150, + 1+DELAY_MASK, TFT_SLPOUT, 255, + 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, + 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, + 1, TFT_INVON, + 1, TFT_DISPON, + 0 +}; + +// VGA constants and variables +// Objective: +// generates VGA signal fully in hardware with as little as possible CPU help + +// Principle: +// QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) +// 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate +// RGB out, combined to create 8bits(/12bits) output. + +// Note: +// - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels +// - experimental resolution: 352x240,352x480 +// - experimental resolution: 512x240,512x480 (not stable) +// - video memory is allocated using malloc in T4 heap +// - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing +// but tried to be compensated by pixel shifting +// - Default is 8bits RRRGGGBB (332) +// But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! +// - Only ok at 600MHz else some disturbances visible + + + +#define TOP_BORDER 40 +#define PIN_HBLANK 15 + +#define PIN_R_B2 33 +#define PIN_R_B1 4 +#define PIN_R_B0 3 +#define PIN_G_B2 2 +#define PIN_G_B1 13 +#define PIN_G_B0 11 +#define PIN_B_B1 12 +#define PIN_B_B0 10 + + +#define DMA_HACK 0x80 + +#define R16(rgb) ((rgb>>8)&0xf8) +#define G16(rgb) ((rgb>>3)&0xfc) +#define B16(rgb) ((rgb<<3)&0xf8) + +// VGA 640x480@60Hz +// Screen refresh rate 60 Hz +// Vertical refresh 31.46875 kHz +// Pixel freq. 25.175 MHz +// +// Visible area 640 25.422045680238 us +// Front porch 16 0.63555114200596 us +// Sync pulse 96 3.8133068520357 us +// Back porch 48 1.9066534260179 us +// Whole line 800 31.777557100298 us + +#define frame_freq 60.0 // Hz +#define line_freq 31.46875 // KHz +#define pix_freq (line_freq*800) // KHz (25.175 MHz) + +// pix_period = 39.7ns +// H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) +#define frontporch_pix 20 //16 +#define backporch_pix 44 //48 + +// Flexio Clock +// PLL3 SW CLOCK (3) => 480 MHz +// PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) +#define FLEXIO_CLK_SEL_PLL3 3 +#define FLEXIO_CLK_SEL_PLL5 2 + +/* Set video PLL */ +// There are /1, /2, /4, /8, /16 post dividers for the Video PLL. +// The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, +// and CCM_ANALOG_MISC2 register sets according to the following equation. +// PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + +// nfact: +// This field controls the PLL loop divider. +// Valid range for DIV_SELECT divider value: 27~54. + +#define POST_DIV_SELECT 2 + +// Full buffer including back/front porch +static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; +static uint32_t dstbuffer __attribute__((aligned(32))); + +// Visible vuffer +static vga_pixel * vga_buffer; +static int vga_width; +static int vga_height; +static int vga_stride; + +static int maxpixperline; +static int left_border; +static int right_border; +static int line_double; +static int pix_shift; +static int ref_div_select; +static int ref_freq_num; +static int ref_freq_denom; +static int ref_pix_shift; +static int combine_shiftreg; + +#ifdef DEBUG +static uint32_t ISRTicks_prev = 0; +volatile uint32_t ISRTicks = 0; +#endif + +uint8_t T4_DSP::_rst; +uint8_t T4_DSP::_cs; +uint8_t T4_DSP::_dc; +uint8_t T4_DSP::_mosi; +uint8_t T4_DSP::_sclk; +uint8_t T4_DSP::_vsync_pin = -1; +DMAChannel T4_DSP::flexio1DMA; +DMAChannel T4_DSP::flexio2DMA; + +static volatile uint32_t VSYNC = 0; +static volatile uint32_t currentLine=0; +#define NOP asm volatile("nop\n\t"); +static gfx_mode_t gfxmode = MODE_UNDEFINED; + + +FASTRUN void T4_DSP::TFT_isr(void) { + dmatx.clearInterrupt(); + curTransfer++; + if (curTransfer >= nbTransfer) { + curTransfer = 0; + if (cancelled) { + dmatx.disable(); + rstop = 1; + } + } + arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); +} + +FASTRUN void T4_DSP::QT3_isr(void) { + TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); + TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); + + cli(); + + // V-PULSE + if (currentLine > 0) { + digitalWrite(_vsync_pin, 1); + VSYNC = 0; + } else { + digitalWrite(_vsync_pin, 0); + VSYNC = 1; + } + + currentLine++; + currentLine = currentLine % 525; + + + uint32_t y = (currentLine - TOP_BORDER) >> line_double; + // Visible area + + if (y >= 0 && y < vga_height) { + // Disable DMAs + //DMA_CERQ = flexio2DMA.channel; + //DMA_CERQ = flexio1DMA.channel; + + // Setup source adress + // Aligned 32 bits copy + unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; + flexio2DMA.TCD->SADDR = p; + if (pix_shift & DMA_HACK) + { + // Unaligned copy + uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; + flexio1DMA.TCD->SADDR = p2; + } + else { + p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 + flexio1DMA.TCD->SADDR = p; + } + + // Enable DMAs + //flexio2DMA.enable(); + //flexio1DMA.enable(); + DMA_SERQ = flexio2DMA.channel; + DMA_SERQ = flexio1DMA.channel; + arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); + } + sei(); + +#ifdef DEBUG + ISRTicks++; +#endif + asm volatile("dsb"); +} + +static void setDmaStruct() { + uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; + uint16_t * fb = (uint16_t*)malloc(remaining); + tft_buffer = fb; + tft_width = TFT_WIDTH; + tft_height = TFT_HEIGHT; + tft_stride = TFT_WIDTH; + uint16_t col=RGBVAL16(0x00,0x00,0x00); + int i=0; + while (remaining > 0) { + int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); + blocks[i] = fb; + for (int j=0;jATTR_DST = 1; + dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); + dmasettings[i].interruptAtCompletion(); + fb += len/2; + remaining -= len; + i++; + } + dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); + nbTransfer = i; +} + +static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 +{ +//if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; + CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE + | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 + | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); + CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; + CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock + const int div_post_pll = 1; // other values: 2,4 + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass +} + +T4_DSP::T4_DSP() +{ + _cs = TFT_CS; + _dc = TFT_DC; + _rst = TFT_RST; + _mosi = TFT_MOSI; + _sclk = TFT_SCLK; + pinMode(_dc, OUTPUT); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, 1); + digitalWrite(_dc, 1); + _vsync_pin = 8; +} + + +void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { + int dx=0; + int dy=0; + digitalWrite(_dc, 0); + SPI.transfer(TFT_CASET); + digitalWrite(_dc, 1); + SPI.transfer16(x1+dx); + digitalWrite(_dc, 1); + SPI.transfer16(x2+dx); + digitalWrite(_dc, 0); + SPI.transfer(TFT_PASET); + digitalWrite(_dc, 1); + SPI.transfer16(y1+dy); + digitalWrite(_dc, 1); + SPI.transfer16(y2+dy); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + return; +} + +void T4_DSP::tft_setup(bool isST) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + // RESET if reset pin defined + if (_rst != 0xff) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + const uint8_t *addr = init_commands; + uint8_t count; + digitalWrite(_cs, 0); + while (count = *addr++) { + uint8_t command = *addr++; + if ( (command == TFT_INVON) && (!isST) ) { + // Skip TFT_INVON for ILI + } + else { + digitalWrite(_dc, 0); // command + SPI.transfer(command); + uint16_t ms = count & DELAY_MASK; + count &= ~DELAY_MASK; + while (--count > 0) { // data + uint8_t data = *addr++; + if ( (command == TFT_MADCTL) && (isST) ) { + data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; + } + digitalWrite(_dc, 1); + SPI.transfer(data); + } + if (ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + digitalWrite(_cs, 1); + SPI.endTransaction(); + delay(2); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + } + } + } + digitalWrite(_cs, 1); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + SPI.endTransaction(); + /* + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_dc, 0); + digitalWrite(_cs, 0); + SPI.transfer(TFT_MADCTL); + digitalWrite(_dc, 1); + SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); + // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); + digitalWrite(_cs, 1); + SPI.endTransaction(); + */ + cancelled = false; +} + +// display VGA image +gfx_error_t T4_DSP::begin(gfx_mode_t mode) +{ + uint32_t flexio_clock_div; + combine_shiftreg = 0; +// int div_select = 49; +// int num = 135; +// int denom = 100; + int div_select = 20; + int num = 9800; + int denom = 10000; + int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; + int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; + set_videoClock(div_select,num,denom,true); + +#ifdef DEBUG + Serial.println(mode); + Serial.println("mode"); +#endif + + switch(mode) + { + case MODE_TFTILI_320x240: +#ifdef DEBUG + Serial.println("TFTILI_320x240"); +#endif + tft_setup(false); + gfxmode = mode; + break; + case MODE_TFTST_320x240: +#ifdef DEBUG + Serial.println("TFTST_320x240"); +#endif + tft_setup(true); + gfxmode = mode; + break; + + case MODE_VGA_320x240: +#ifdef DEBUG + Serial.println("VGA_320x240"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_320x480: +#ifdef DEBUG + Serial.println("VGA_320x480"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_640x240: +#ifdef DEBUG + Serial.println("VGA_640x240"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/pix_freq; + line_double = 1; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_640x480: +#ifdef DEBUG + Serial.println("VGA_640x480"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = (flexio_freq/pix_freq); + line_double = 0; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_512x240: +#ifdef DEBUG + Serial.println("VGA_512x240"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 1; + pix_shift = 0; + break; + + case MODE_VGA_512x480: +#ifdef DEBUG + Serial.println("VGA_512x480"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 0; + pix_shift = 0; + break; + + case MODE_VGA_352x240: +#ifdef DEBUG + Serial.println("VGA_352x240"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_352x480: +#ifdef DEBUG + Serial.println("VGA_352x480"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + } + + if (mode >= MODE_VGA_320x240) + { + if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { + fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); + digitalWrite(_cs, 0); + digitalWrite(_dc, 0); + SPI.transfer(TFT_DISPOFF); + digitalWrite(_cs, 1); + delay(20); + digitalWrite(_cs, 0); + digitalWrite(_cs, 1); + } + gfxmode = mode; + + maxpixperline = vga_stride; + // Save param for tweek adjustment + ref_div_select = div_select; + ref_freq_num = num; + ref_freq_denom = denom; + ref_pix_shift = pix_shift; + +#ifdef DEBUG + Serial.println("frequency"); + Serial.println(flexio_freq); + Serial.println("div"); + Serial.println(flexio_freq/pix_freq); +#endif + + pinMode(_vsync_pin, OUTPUT); + pinMode(PIN_HBLANK, OUTPUT); + + /* Basic pin setup FlexIO1 */ + pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 + pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 + pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 + pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 + /* Basic pin setup FlexIO2 */ + pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 + pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 + pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 + pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 + + /* High speed and drive strength configuration */ + *(portControlRegister(PIN_G_B2)) = 0xFF; + *(portControlRegister(PIN_R_B0)) = 0xFF; + *(portControlRegister(PIN_R_B1)) = 0xFF; + *(portControlRegister(PIN_R_B2)) = 0xFF; + *(portControlRegister(PIN_B_B0)) = 0xFF; + *(portControlRegister(PIN_B_B1)) = 0xFF; + *(portControlRegister(PIN_G_B0)) = 0xFF; + *(portControlRegister(PIN_G_B1)) = 0xFF; + + /* Set clock for FlexIO1 and FlexIO2 */ + CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) + | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); + CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) + | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); + + + /* Set up pin mux FlexIO1 */ + *(portConfigRegister(PIN_G_B2)) = 0x14; + *(portConfigRegister(PIN_R_B0)) = 0x14; + *(portConfigRegister(PIN_R_B1)) = 0x14; + *(portConfigRegister(PIN_R_B2)) = 0x14; + /* Set up pin mux FlexIO2 */ + *(portConfigRegister(PIN_B_B0)) = 0x14; + *(portConfigRegister(PIN_B_B1)) = 0x14; + *(portConfigRegister(PIN_G_B0)) = 0x14; + *(portConfigRegister(PIN_G_B1)) = 0x14; + + /* Enable the clock */ + CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + /* Enable the FlexIO with fast access */ + FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + + uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; + uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; + + /* Shifter 0 registers for FlexIO2 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 + inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter + stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled + startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable + timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 + timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock + pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output + pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity + shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode + /* Shifter 0 registers for FlexIO1 */ + FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + /* Shifter 0 registers for FlexIO1 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 + FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + if (combine_shiftreg) { + pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled + FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + } + /* Timer 0 registers for FlexIO2 */ + timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset + timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output + timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset + timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare + timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert + stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled + startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled + if (combine_shiftreg) { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag + } + else { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag + } + triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low + triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected + pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled + //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 + //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high + timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode + // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) + + int shifts_per_transfer; + if (combine_shiftreg) { + shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 + } + else { + shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 + } + FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); + /* Timer 0 registers for FlexIO1 */ + FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); +#ifdef DEBUG + Serial.println("FlexIO setup complete"); +#endif + + /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ + if (combine_shiftreg) { + FLEXIO2_SHIFTSDEN |= (1<<1); + FLEXIO1_SHIFTSDEN |= (1<<1); + } + else { + FLEXIO2_SHIFTSDEN |= (1<<0); + FLEXIO1_SHIFTSDEN |= (1<<0); + } + /* Disable DMA channel so it doesn't start transferring yet */ + flexio1DMA.disable(); + flexio2DMA.disable(); + /* Set up DMA channel to use Shifter 0 trigger */ + flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); + flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); + + + if (combine_shiftreg) { + flexio2DMA.TCD->NBYTES = 8; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 8; + flexio2DMA.TCD->CITER = maxpixperline / 8; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + flexio1DMA.TCD->NBYTES = 8; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 8; + flexio1DMA.TCD->CITER = maxpixperline / 8; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Setup DMA2 Flexio2 copy + flexio2DMA.TCD->NBYTES = 4; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 4; + flexio2DMA.TCD->CITER = maxpixperline / 4; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + // Setup DMA1 Flexio1 copy + // Use pixel shift to avoid color smearing? + if (pix_shift & DMA_HACK) + { + if (pix_shift & 0x3 == 0) { + // Aligned 32 bits copy (32bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Unaligned (source) 32 bits copy (8bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 1; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion + } + } + else + { + // Aligned 32 bits copy + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + } + +#ifdef DEBUG + Serial.println("DMA setup complete"); +#endif + + // enable clocks for QTIMER3: generates the 15KHz for hsync + // Pulse: + // low : 3.8133 us => 569x6.7ns + // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) + // (OLD TEST) + // (4us low, 28us high => 32us) + // (597x6.7ns for 4us) + // (4179x6.7ns for 28us) + CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 + //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 + + #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz + #define MARGIN_D 1000 + + TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer + // Invert output pin as we want the interupt on rising edge + TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) + TMR3_CNTR3 = 0; + TMR3_LOAD3 = 0; + + /* Inverted timings */ + unsigned long long cpu_freq = F_CPU; + unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; + int rate2 = rate; + + int substract = 1; + if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { + substract=5; + rate2=1652; + } + + #ifdef DEBUG + Serial.print("MARGIN_N is: "); + Serial.println(rate2, DEC); + Serial.print("SUBSTRACT is: "); + Serial.println(substract, DEC); +#endif + TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; + TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; + /* + TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; + */ + TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on + TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), + // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) + //configure Teensy pin Compare output + IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 + attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function + NVIC_ENABLE_IRQ(IRQ_QTIMER3); +#ifdef DEBUG + Serial.println("QTIMER3 setup complete"); + Serial.print("V-PIN is "); + Serial.println(_vsync_pin); +#endif + + /* initialize gfx buffer */ + if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift + if (gfxbuffer == NULL) return(GFX_ERROR); +#ifdef DEBUG + Serial.println("Memory allocated"); +#endif + + memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); + vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; +#ifdef DEBUG + Serial.println(vga_stride); + Serial.println(vga_height); + Serial.println("Screen cleared"); +#endif + } + + return(GFX_OK); +} + +gfx_mode_t T4_DSP::getMode(void) +{ + return gfxmode; +} + +void T4_DSP::startRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + curTransfer = 0; + rstop = 0; + //dmatx.begin(true); + dmatx.attachInterrupt(TFT_isr); + setDmaStruct(); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + + digitalWrite(_cs, HIGH); + SPI.begin(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + + LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: + LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX + LPSPIP_TCR = 15; // Framesize 16 Bits + //LPSPIP_FCR = 0; // Fifo Watermark + LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable + LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: + dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); + + dmatx = dmasettings[0]; + digitalWrite(_cs, 0); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + dmatx.enable(); + } +} + + +void T4_DSP::stopRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + rstop = 1; + unsigned long m = millis(); + cancelled = true; + while (!rstop) { + if ((millis() - m) > 100) break; + delay(10); + asm volatile("wfi"); + }; + rstop = 0; + delay(50); + cancelled = false; + dmatx.detachInterrupt(); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + SPI.end(); +#ifdef ST7789 +// begin(gfxmode); +#endif + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + } +} + +int T4_DSP::get_frame_buffer_size(int *width, int *height) { + if (gfxmode < MODE_VGA_320x240) { + if (width != nullptr) *width = tft_width; + if (height != nullptr) *height = tft_height; + return tft_stride; + } + else { + if (width != nullptr) *width = vga_width; + if (height != nullptr) *height = vga_height; + return vga_stride; + } +} + +void T4_DSP::waitSync() +{ + if (gfxmode >= MODE_VGA_320x240) { + while (VSYNC == 0) {}; + } +} + +void T4_DSP::waitLine(int line) +{ + if (gfxmode >= MODE_VGA_320x240) { + while (currentLine != line) {}; + } +} + +/*********************************************************************************************** + No DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreenNoDma(uint16_t color) { + if (gfxmode < MODE_VGA_320x240) { + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + int i,j; + for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(arx, ary, arx+arw-1, ary+arh-1); + bitmap = bitmap + bmp_offy*w + bmp_offx; + for (int row=0;row> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + bits = *charpt++; + //digitalWrite(_dc, 1); + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + x +=8; + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + else { + drawText(x, y, text, fgcolor, bgcolor, doublesize); + } +} + + +/*********************************************************************************************** + DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreen(uint16_t color) { + int i,j; + if (gfxmode < MODE_VGA_320x240) { + for (j=0; j> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + dst=&tft_buffer[l*tft_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + x +=8; + } + } + else { + vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); + vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); + vga_pixel * dst; + while ((c = *text++)) { + const unsigned char * charpt=&font8x8[c][0]; + int l=y; + for (int i=0;i<8;i++) + { + unsigned char bits; + if (doublesize) { + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + x +=8; + } + } +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { + drawSprite(x,y,bitmap, 0,0,0,0); +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) +{ + int bmp_offx = 0; + int bmp_offy = 0; + uint16_t *bmp_ptr; + int w =*bitmap++; + int h = *bitmap++; + if ( (arw == 0) || (arh == 0) ) { + // no crop window + arx = x; + ary = y; + arw = w; + arh = h; + } + else { + if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + int l=ary; + bitmap = bitmap + bmp_offy*w + bmp_offx; + + if (gfxmode < MODE_VGA_320x240) { + for (int row=0;row tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]; + pos +=step; + } + #endif + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i 2) ) y += (tft_height-height)/2; + uint16_t * dst=&tft_buffer[y*tft_stride]; + if (width > tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]]; + pos +=step; + } +#endif + } + else if ((width*2) == tft_width) { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]]; + *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i tft_width) { + int step = ((width << 8)/tft_width); + int pos = 0; + for (int i=0; i> 8]]; + pos +=step; + } + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = pix; + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i +#include +#endif + +#include "platform_config.h" +#include "iopins.h" + + + +#ifndef TFT_WIDTH +#define TFT_WIDTH 320 +#endif +#define TFT_REALWIDTH 320 + +#ifndef TFT_HEIGHT +#define TFT_HEIGHT 240 +#endif +#define TFT_REALHEIGHT 240 + + +typedef enum gfx_mode_t +{ + MODE_UNDEFINED = 0, + MODE_TFTILI_320x240 = 1, + MODE_TFTST_320x240 = 2, + MODE_VGA_320x240 = 3, + MODE_VGA_320x480 = 4, + MODE_VGA_352x240 = 5, + MODE_VGA_352x480 = 6, + MODE_VGA_512x240 = 7, + MODE_VGA_512x480 = 8, + MODE_VGA_640x240 = 9, + MODE_VGA_640x480 = 10 +} gfx_mode_t; + +typedef enum gfx_error_t +{ + GFX_OK = 0, + GFX_ERROR = -1 +} gfx_error_t; + + +#ifdef __cplusplus + +class T4_DSP +{ + public: + T4_DSP(); + + gfx_error_t begin(gfx_mode_t mode); + gfx_mode_t getMode(void); + void startRefresh(void); + void stopRefresh(); + + int get_frame_buffer_size(int *width, int *height); + void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); + + // wait next Vsync + void waitSync(); + void waitLine(int line); + + // NoDMA functions + void fillScreenNoDma(uint16_t color); + void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + // DMA functions + void fillScreen(uint16_t color); + void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + void writeLine(int width, int height, int y, uint16_t *buf); + void writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + void writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16); + void writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + + protected: + static uint8_t _rst, _cs, _dc; + static uint8_t _mosi, _sclk; + static uint8_t _vsync_pin; + static DMAChannel flexio1DMA; + static DMAChannel flexio2DMA; + void tft_setup(bool isST); + static void TFT_isr(void); + static void QT3_isr(void); +}; + +#endif +#endif diff --git a/MCUME_teensy41/teensylogo/teensylogo.ino b/MCUME_teensy41/teensylogo/teensylogo.ino index 3161367..6dffc26 100644 --- a/MCUME_teensy41/teensylogo/teensylogo.ino +++ b/MCUME_teensy41/teensylogo/teensylogo.ino @@ -6,42 +6,37 @@ extern "C" { #include #include "mcume.h" +#include "t4_dsp.h" +extern T4_DSP tft; -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -TFT_T_DMA tft; -#else -#include "tft_t_dma.h" -TFT_T_DMA tft = TFT_T_DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, TFT_TOUCH_CS, TFT_TOUCH_INT); -#endif static int xOffLogo=0; static int swipeAngle=0; +// **************************************************** +// the setup() method runs once, when the sketch starts +// **************************************************** void setup() { - //emu_sndInit(); -#ifdef HAS_T4_VGA - tft.begin(VGA_MODE_320x240); -// NVIC_SET_PRIORITY(IRQ_QTIMER3, 0); -#else - tft.begin(); -#endif - emu_init(); + emu_init(); } -static uint8_t col=0x00; +static void vbl(void) { + uint16_t bClick = emu_DebounceLocalKeys(); + emu_Input(bClick); +} +// **************************************************** +// the loop() method runs continuously +// **************************************************** void loop(void) { - - uint16_t bClick = emu_DebounceLocalKeys(); if (menuActive()) { + uint16_t bClick = emu_DebounceLocalKeys(); int action = handleMenu(bClick); char * filename = menuSelection(); - if (action == ACTION_RUN1) { - toggleMenu(false); - tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00)); - tft.startDMA(); + if (action == ACTION_RUN1) { + emu_start(16666,nullptr); + emu_Init(filename); tft.drawRect(0,TFT_HEIGHT/2, TFT_WIDTH, TFT_HEIGHT/2, RGBVAL16(0x00,0x00,0x80)); tft.drawText(0,TFT_HEIGHT/2, "hello hello hello hello hello hello hell", RGBVAL16(0x00,0xff,0xff), RGBVAL16(0x00,0x00,0xff), true); tft.drawText(0,TFT_HEIGHT/2+16, "hello hello hello hello hello hello hell", RGBVAL16(0x00,0xff,0xff), RGBVAL16(0x00,0x00,0xff), false); @@ -50,60 +45,20 @@ void loop(void) tft.drawText(0,TFT_HEIGHT/2+40, "hello hello hello hello hello hello hell", RGBVAL16(0x00,0xff,0xff), RGBVAL16(0x00,0x00,0xff), false); tft.drawText(0,TFT_HEIGHT/2+48, "hello hello hello hello hello hello hell", RGBVAL16(0x00,0xff,0xff), RGBVAL16(0x00,0x00,0xff), false); tft.drawText(0,TFT_HEIGHT/2+56, "hello hello hello hello hello hello hell", RGBVAL16(0x00,0xff,0xff), RGBVAL16(0x00,0x00,0xff), false); - tft.drawText(0,TFT_HEIGHT/2+64, "hello hello hello hello hello hello hell", RGBVAL16(0x00,0xff,0xff), RGBVAL16(0x00,0x00,0xff), false); + tft.drawText(0,TFT_HEIGHT/2+64, "hello hello hello hello hello hello hell", RGBVAL16(0x00,0xff,0xff), RGBVAL16(0x00,0x00,0xff), false); } delay(20); } - else { - delay(20); + else { + uint16_t bClick = emu_DebounceLocalKeys(); xOffLogo = 16*sin((2*3.14*swipeAngle)/256)+30; swipeAngle = (swipeAngle + 4)&0xff; tft.drawSprite(xOffLogo,10,(uint16_t*)logo); - if (bClick & MASK_JOY2_BTN) { - tft.stopDMA(); - emu_init(); - toggleMenu(true); - } + //if (bClick & MASK_JOY2_BTN) { + // tft.stopRefresh(); + // emu_init(); + // toggleMenu(true); + //} + delay(20); } } - -void emu_KeyboardOnDown(int keymodifer, int key) { -} - -void emu_KeyboardOnUp(int keymodifer, int key) { -} - -#ifdef HAS_SND - -#include "AudioPlaySystem.h" - -AudioPlaySystem mymixer; - - -void emu_sndInit() { - Serial.println("sound init"); - mymixer.begin_audio(256, mymixer.snd_Mixer); - mymixer.start(); -} - -void emu_sndPlaySound(int chan, int volume, int freq) -{ - if (chan < 6) { - mymixer.sound(chan, freq, volume); - } - /* - Serial.print(chan); - Serial.print(":" ); - Serial.print(volume); - Serial.print(":" ); - Serial.println(freq); - */ -} - -void emu_sndPlayBuzz(int size, int val) { - mymixer.buzz(size,val); - //Serial.print((val==1)?1:0); - //Serial.print(":"); - //Serial.println(size); -} -#endif diff --git a/MCUME_teensy41/teensylogo/tft_t_dma.cpp b/MCUME_teensy41/teensylogo/tft_t_dma.cpp deleted file mode 100644 index 176962e..0000000 --- a/MCUME_teensy41/teensylogo/tft_t_dma.cpp +++ /dev/null @@ -1,1243 +0,0 @@ -/* - Based on C64 ILI9341 dma driver from Frank Bösing, 2017 -*/ - -#include "TFT_T_DMA.h" - -#ifndef HAS_T4_VGA - -#include "font8x8.h" - -// LPSPI4 = SPI0 in Teensy 4.0 -// LPSPI3 = SPI1 in Teensy 4.0 -// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) -#ifdef TFTSPI1 -#define SPI SPI1 -#define LPSPIP_TDR LPSPI3_TDR -#define LPSPIP_CR LPSPI3_CR -#define LPSPIP_CFGR1 LPSPI3_CFGR1 -#define LPSPIP_TCR LPSPI3_TCR -#define LPSPIP_DER LPSPI3_DER -#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX -#else -#define LPSPIP_TDR LPSPI4_TDR -#define LPSPIP_CR LPSPI4_CR -#define LPSPIP_CFGR1 LPSPI4_CFGR1 -#define LPSPIP_TCR LPSPI4_TCR -#define LPSPIP_DER LPSPI4_DER -#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX -#endif - - -#define SPICLOCK 60000000 //144e6 //Just a number..max speed -#ifdef ILI9341 -#define SPI_MODE SPI_MODE0 -#endif -#ifdef ST7789 -#define SPI_MODE SPI_MODE2 -#endif - -// touch -#define SPI_SETTING SPISettings(2500000, MSBFIRST, SPI_MODE) -#define XPT2046_CFG_START _BV(7) -#define XPT2046_CFG_MUX(v) ((v&0b111) << (4)) -#define XPT2046_CFG_8BIT _BV(3) -#define XPT2046_CFG_12BIT (0) -#define XPT2046_CFG_SER _BV(2) -#define XPT2046_CFG_DFR (0) -#define XPT2046_CFG_PWR(v) ((v&0b11)) -#define XPT2046_MUX_Y 0b101 -#define XPT2046_MUX_X 0b001 -#define XPT2046_MUX_Z1 0b011 -#define XPT2046_MUX_Z2 0b100 - - -#ifdef TFT_STATICFB -static uint16_t fb0[LINES_PER_BLOCK*TFT_WIDTH]; -static uint16_t fb1[LINES_PER_BLOCK*TFT_WIDTH]; -static uint16_t fb2[LINES_PER_BLOCK*TFT_WIDTH]; -static uint16_t fb3[(TFT_HEIGHT-3*LINES_PER_BLOCK)*TFT_WIDTH]; -static uint16_t * blocks[NR_OF_BLOCK]={fb0,fb1,fb2,fb3}; -#else -static uint16_t * blocks[NR_OF_BLOCK]; -#endif - - -static DMASetting dmasettings[SCREEN_DMA_NUM_SETTINGS]; -static DMAChannel dmatx;//(false); -static volatile uint8_t rstop = 0; -static volatile bool cancelled = false; -static volatile uint8_t curTransfer = 0; -static uint8_t nbTransfer = 0; - - -PROGMEM static const uint8_t init_commands[] = { -#ifdef ILI9341 - 4, 0xEF, 0x03, 0x80, 0x02, - 4, 0xCF, 0x00, 0XC1, 0X30, - 5, 0xED, 0x64, 0x03, 0X12, 0X81, - 4, 0xE8, 0x85, 0x00, 0x78, - 6, 0xCB, 0x39, 0x2C, 0x00, 0x34, 0x02, - 2, 0xF7, 0x20, - 3, 0xEA, 0x00, 0x00, - 2, ILI9341_PWCTR1, 0x23, // Power control - 2, ILI9341_PWCTR2, 0x10, // Power control - 3, ILI9341_VMCTR1, 0x3e, 0x28, // VCM control - 2, ILI9341_VMCTR2, 0x86, // VCM control2 - 2, ILI9341_MADCTL, 0x48, // Memory Access Control - 2, ILI9341_PIXFMT, 0x55, - 3, ILI9341_FRMCTR1, 0x00, 0x18, - 4, ILI9341_DFUNCTR, 0x08, 0x82, 0x27, // Display Function Control - 2, 0xF2, 0x00, // Gamma Function Disable - 2, ILI9341_GAMMASET, 0x01, // Gamma curve selected - 16, ILI9341_GMCTRP1, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, - 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, // Set Gamma - 16, ILI9341_GMCTRN1, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, - 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, // Set Gamma -// 3, 0xb1, 0x00, 0x1f, // FrameRate Control 61Hz - 3, 0xb1, 0x00, 0x10, // FrameRate Control 119Hz - 2, ILI9341_MADCTL, ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR, - 0 -#endif -#ifdef ST7789 -#define DELAY 0x80 - 9, // 9 commands in list: - ST7735_SWRESET, DELAY, // 1: Software reset, no args, w/delay - 150, // 150 ms delay - ST7735_SLPOUT , DELAY, // 2: Out of sleep mode, no args, w/delay - 255, // 255 = 500 ms delay - ST7735_COLMOD , 1+DELAY, // 3: Set color mode, 1 arg + delay: - 0x55, // 16-bit color - 10, // 10 ms delay - ST7735_MADCTL , 1 , // 4: Memory access ctrl (directions), 1 arg: - 0x08, // Row addr/col addr, bottom to top refresh - ST7735_CASET , 4 , // 5: Column addr set, 4 args, no delay: - 0x00, - 0x00, // XSTART = 0 - 0x00, - 240, // XEND = 240 - ST7735_RASET , 4 , // 6: Row addr set, 4 args, no delay: - 0x00, - 0x00, // YSTART = 0 - 320>>8, - 320 & 0xFF, // YEND = 320 - ST7735_INVON , DELAY, // 7: hack - 10, - ST7735_NORON , DELAY, // 8: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 9: Main screen turn on, no args, w/delay - 255 -#endif -}; - -static void dmaInterrupt() { - dmatx.clearInterrupt(); - curTransfer++; - if (curTransfer >= nbTransfer) { - curTransfer = 0; - if (cancelled) { - dmatx.disable(); - rstop = 1; - } - } - arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2); -} - -static void setDmaStruct() { - uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; - int i=0; - uint16_t col=RGBVAL16(0x00,0x00,0x00);; - while (remaining > 0) { - uint16_t * fb = blocks[i]; - int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining); -#ifdef TFT_DEBUG - Serial.println((unsigned long)blocks[i]); - Serial.println(remaining); -#endif - switch (i) { - case 0: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb0[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0x00); -#endif - break; - case 1: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb1[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0xff); -#endif - break; - case 2: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb2[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0x00,0xff); -#endif - break; - case 3: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb3[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0xff,0x00,0xff); -#endif - break; - } - blocks[i] = fb; - if (blocks[i] == 0) { - Serial.print("ILI9341 allocaltion failed for block "); - Serial.println(i); - delay(10000); - } - - for (int j=0;jATTR_DST = 1; - dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); - dmasettings[i].interruptAtCompletion(); - remaining -= len; - i++; - } - dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); - nbTransfer = i; -#ifdef TFT_DEBUG - Serial.println(nbTransfer); -#endif -} - - -TFT_T_DMA::TFT_T_DMA(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso, uint8_t touch_cs, uint8_t touch_irq) -{ - _cs = cs; - _dc = dc; - _rst = rst; - _mosi = mosi; - _sclk = sclk; - _miso = miso; - pinMode(_dc, OUTPUT); - pinMode(_cs, OUTPUT); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); - if ( (touch_cs != 255) && (touch_irq != 255) ) { - _touch_irq = touch_irq; - _touch_cs = touch_cs; - pinMode(_touch_cs, OUTPUT); - pinMode(touch_irq, INPUT_PULLUP); - digitalWrite(_touch_cs, 1); - } -} - - -void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { - int dx=0; - int dy=0; -#ifdef ST7789 - if (TFT_REALWIDTH == TFT_REALHEIGHT) - { -#ifdef ROTATE_SCREEN - if (!flipped) { - dy += 80; - } -#else - if (flipped) { - dx += 80; - } -#endif - } -#endif - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - SPI.transfer16(x1+dx); - digitalWrite(_dc, 1); - SPI.transfer16(x2+dx); - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - digitalWrite(_dc, 1); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - return; - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - - SPI.transfer16(x1+dx); - SPI.transfer16(x2+dx); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - -void TFT_T_DMA::begin(void) { - SPI.setMOSI(_mosi); - SPI.setMISO(_miso); - SPI.setSCK(_sclk); - SPI.begin(); - - // Initialize display - if (_rst != 0xff) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - const uint8_t *addr = init_commands; - digitalWrite(_cs, 0); -#ifdef ILI9341 - while (1) { - uint8_t count = *addr++; - if (count-- == 0) break; - - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - - while (count-- > 0) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - } - - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(ILI9341_DISPON); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); -#endif -#ifdef ST7789 - uint8_t numCommands, numArgs; - uint16_t ms; - numCommands = *addr++; // Number of commands to follow - while(numCommands--) { // For each command... - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - numArgs = *addr++; // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs > 1) { // For each argument... - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - numArgs--; - } - - if (numArgs) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - if(ms) { - ms = *addr++; // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - digitalWrite(_cs, 1); - SPI.endTransaction(); - delay(ms); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - } - } - digitalWrite(_cs, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - SPI.endTransaction(); - - cancelled = false; - -#ifdef FLIP_SCREEN - flipscreen(true); -#else - flipscreen(false); -#endif -#ifdef ST7789 - if (TFT_REALWIDTH != TFT_REALHEIGHT) - { - flipscreen(true); - } -#endif -}; - - - -void TFT_T_DMA::flipscreen(bool flip) -{ - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(TFT_MADCTL); - digitalWrite(_dc, 1); - if (flip) { - flipped=true; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB); -#endif -#endif - } - else { - flipped=false; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB); -#endif -#endif - } - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - -boolean TFT_T_DMA::isflipped(void) -{ - return(flipped); -} - - -#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) - - -void TFT_T_DMA::startDMA(void) { - curTransfer = 0; - rstop = 0; - //dmatx.begin(true); - dmatx.attachInterrupt(dmaInterrupt); - setDmaStruct(); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - - digitalWrite(_cs, HIGH); - SPI.begin(); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); - - - LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: - LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX - LPSPIP_TCR = 15; // Framesize 16 Bits - //LPSPIP_FCR = 0; // Fifo Watermark - LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable - LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: - dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); - - dmatx = dmasettings[0]; - digitalWrite(_cs, 0); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - dmatx.enable(); -} - - -void TFT_T_DMA::stopDMA(void) { - rstop = 0; - wait(); - delay(50); - cancelled = false; - dmatx.detachInterrupt(); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - SPI.end(); -#ifdef ST7789 - begin(); -#endif -#ifdef ILI9341 - SPI.begin(); - digitalWrite(_cs, 0); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - SPI.endTransaction(); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); -} - -void TFT_T_DMA::wait(void) { - rstop = 1; - unsigned long m = millis(); - cancelled = true; - while (!rstop) { - if ((millis() - m) > 100) break; - delay(10); - asm volatile("wfi"); - }; - rstop = 0; -} - -int TFT_T_DMA::get_frame_buffer_size(int *width, int *height){ - if (width != nullptr) *width = TFT_REALWIDTH; - if (height != nullptr) *height = TFT_REALHEIGHT; - return TFT_REALWIDTH; -} - - -/*********************************************************************************************** - Touch functions - ***********************************************************************************************/ -/* Code based on ... - * - * @file XPT2046.cpp - * @date 19.02.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the XPT2046 driver for Arduino. - */ - -#define ADC_MAX 0x0fff - -void TFT_T_DMA::enableTouchIrq() -{ - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 }; - SPI.transfer((void*)&buf[0],3); - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); -} - -//Default callibration for non flipped -#define TX_MIN 30 -#define TY_MIN 20 -#define TX_MAX 300 -#define TY_MAX 220 - -//Default callibration for flipped -#define TFX_MIN 20 -#define TFY_MIN 25 -#define TFX_MAX 288 -#define TFY_MAX 221 - -static uint16_t txMin; -static uint16_t tyMin; -static uint16_t txMax; -static uint16_t tyMax; - - -void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { - if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) { - txMin = xMin; - tyMin = yMin; - txMax = xMax; - tyMax = yMax; - } - else { - if (flipped) { - txMin = TFX_MIN; - tyMin = TFY_MIN; - txMax = TFX_MAX; - tyMax = TFY_MAX; - } - else { - txMin = TX_MIN; - tyMin = TY_MIN; - txMax = TX_MAX; - tyMax = TY_MAX; - } - } -} - - -void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - if ( TOUCH_ENABLED() ) { - uint16_t x = 0; - uint16_t y = 0; - uint16_t z1 = 0; - uint16_t z2 = 0; - uint8_t i = 0; - int16_t xraw=0, yraw=0; - - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - - for(; i < 15; i++) { - // SPI requirer 32bit aliment - uint8_t buf[12] = { - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00 - }; - SPI.transfer(&buf[0], &buf[0], 12); - y += (buf[1] << 8 | buf[2])>>3; - x += (buf[4] << 8 | buf[5])>>3; - z1 += (buf[7] << 8 | buf[8])>>3; - z2 += (buf[10] << 8 | buf[11])>>3; - } - enableTouchIrq(); - - if(i == 0) { - *oX = 0; - *oY = 0; - *oZ = 0; - } - else { - x /= i; - y /= i; - z1 /= i; - z2 /= i; - } - - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); - int z = z1 + ADC_MAX - z2; - if (flipped) { - xraw = x; - yraw = y; - } else { - xraw = ADC_MAX - x; - yraw = ADC_MAX - y; - } - xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1); - yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1); - - *oX = xraw; - *oY = yraw; - *oZ = z; - } - else - { - *oX = 0; - *oY = 0; - *oZ = 0; - } -} - -void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - readRaw(oX,oY,oZ); - // callibrate ... - if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin); - if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin); - //Serial.print(*oX); - //Serial.print(" "); - //Serial.println(*oY); -} - - -/*********************************************************************************************** - No DMA functions - ***********************************************************************************************/ -void TFT_T_DMA::fillScreenNoDma(uint16_t color) { - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - int i,j; - for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(arx, ary, arx+arw-1, ary+arh-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - bits = *charpt++; - //digitalWrite(_dc, 1); - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - x +=8; -#ifdef ILI9341 - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); -#endif - digitalWrite(_cs, 1); - SPI.endTransaction(); - } - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - - - -/*********************************************************************************************** - DMA functions - ***********************************************************************************************/ -uint16_t * TFT_T_DMA::getLineBuffer(int j) -{ - uint16_t * block=blocks[j>>6]; - return(&block[(j&0x3F)*TFT_REALWIDTH]); -} - -void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) { - uint8_t *buffer=buf; - uint8_t *src; - - int i,j,y=0; - if (width*2 <= TFT_REALWIDTH) { - for (j=0; j>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH]; - for (i=0; i>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x]; - for (i=0; i>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - block=blocks[l>>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt++; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - x +=8; - } -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { - drawSprite(x,y,bitmap, 0,0,0,0); -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) -{ - int bmp_offx = 0; - int bmp_offy = 0; - uint16_t *bmp_ptr; - - int w =*bitmap++; - int h = *bitmap++; - - - if ( (arw == 0) || (arh == 0) ) { - // no crop window - arx = x; - ary = y; - arw = w; - arh = h; - } - else { - if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - int l=ary; - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx]; - bmp_ptr = (uint16_t*)bitmap; - for (int col=0;col -#include -#include -#endif - -#include "tft_t_dma_config.h" - -#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) -#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define R16(rgb) ((rgb>>8)&0xf8) -#define G16(rgb) ((rgb>>3)&0xfc) -#define B16(rgb) ((rgb<<3)&0xf8) - -#define PAL_COLOR_MASK 0xff - -#ifdef LOHRES -#define TFT_WIDTH 240 -#define TFT_REALWIDTH 240 -#else -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 -#endif -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - -//#define WIDTH 272 -//#define HEIGHT 228 - -#define LINES_PER_BLOCK 64 -#define NR_OF_BLOCK 4 -#define SCREEN_DMA_NUM_SETTINGS NR_OF_BLOCK - - -#ifdef ILI9341 - -#define ILI9341_NOP 0x00 -#define ILI9341_SWRESET 0x01 -#define ILI9341_RDDID 0x04 -#define ILI9341_RDDST 0x09 - -#define ILI9341_SLPIN 0x10 -#define ILI9341_SLPOUT 0x11 -#define ILI9341_PTLON 0x12 -#define ILI9341_NORON 0x13 - -#define ILI9341_RDMODE 0x0A -#define ILI9341_RDMADCTL 0x0B -#define ILI9341_RDPIXFMT 0x0C -#define ILI9341_RDIMGFMT 0x0D -#define ILI9341_RDSELFDIAG 0x0F - -#define ILI9341_INVOFF 0x20 -#define ILI9341_INVON 0x21 -#define ILI9341_GAMMASET 0x26 -#define ILI9341_DISPOFF 0x28 -#define ILI9341_DISPON 0x29 - -#define ILI9341_CASET 0x2A -#define ILI9341_PASET 0x2B -#define ILI9341_RAMWR 0x2C -#define ILI9341_RAMRD 0x2E - -#define ILI9341_PTLAR 0x30 -#define ILI9341_MADCTL 0x36 -#define ILI9341_VSCRSADD 0x37 -#define ILI9341_PIXFMT 0x3A - -#define ILI9341_FRMCTR1 0xB1 -#define ILI9341_FRMCTR2 0xB2 -#define ILI9341_FRMCTR3 0xB3 -#define ILI9341_INVCTR 0xB4 -#define ILI9341_DFUNCTR 0xB6 - -#define ILI9341_PWCTR1 0xC0 -#define ILI9341_PWCTR2 0xC1 -#define ILI9341_PWCTR3 0xC2 -#define ILI9341_PWCTR4 0xC3 -#define ILI9341_PWCTR5 0xC4 -#define ILI9341_VMCTR1 0xC5 -#define ILI9341_VMCTR2 0xC7 - -#define ILI9341_RDID1 0xDA -#define ILI9341_RDID2 0xDB -#define ILI9341_RDID3 0xDC -#define ILI9341_RDID4 0xDD - -#define ILI9341_GMCTRP1 0xE0 -#define ILI9341_GMCTRN1 0xE1 - -#define ILI9341_MADCTL_MY 0x80 -#define ILI9341_MADCTL_MX 0x40 -#define ILI9341_MADCTL_MV 0x20 -#define ILI9341_MADCTL_ML 0x10 -#define ILI9341_MADCTL_RGB 0x00 -#define ILI9341_MADCTL_BGR 0x08 -#define ILI9341_MADCTL_MH 0x04 - -#define TFT_CASET ILI9341_CASET -#define TFT_PASET ILI9341_PASET -#define TFT_RAMWR ILI9341_RAMWR -#define TFT_MADCTL ILI9341_MADCTL - -#endif - - -#ifdef ST7789 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_RGB 0x00 -#define ST77XX_MADCTL_BGR 0x08 -#define ST77XX_MADCTL_MH 0x04 - -#define TFT_CASET ST7735_CASET -#define TFT_PASET ST7735_RASET -#define TFT_RAMWR ST7735_RAMWR -#define TFT_MADCTL ST7735_MADCTL - -#endif - - - -#ifdef __cplusplus - -class TFT_T_DMA -{ - public: - TFT_T_DMA(uint8_t _CS, uint8_t _DC, uint8_t _RST = 255, uint8_t _MOSI=11, uint8_t _SCLK=13, uint8_t _MISO=12, uint8_t touch_cs=38, uint8_t touch_irq=37); - - void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); - void begin(void); - void flipscreen(bool flip); - boolean isflipped(void); - void startDMA(void); - void stopDMA(); - int get_frame_buffer_size(int *width, int *height); - - // Touch screen functions - #define TOUCH_ENABLED() ((_touch_cs != 255) && (_touch_irq != 255)) - bool isTouching(void) { return ((!TOUCH_ENABLED())?false:(digitalRead(_touch_irq) == LOW)); } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax); - - // NoDMA functions - void writeScreenNoDma(const uint16_t *pcolors); - void fillScreenNoDma(uint16_t color); - void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - // DMA functions - uint16_t * getLineBuffer(int j); - void writeScreen(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int y, uint16_t *buf); - void fillScreen(uint16_t color); - void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - protected: - uint8_t _rst, _cs, _dc; - uint8_t _miso, _mosi, _sclk; - uint8_t _touch_irq=255, _touch_cs=255; - bool flipped=false; - - void wait(void); - void enableTouchIrq(); -}; - -#endif -#endif - - diff --git a/MCUME_teensy41/teensylogo/tft_t_dma_config.h b/MCUME_teensy41/teensylogo/tft_t_dma_config.h deleted file mode 100644 index d8200a2..0000000 --- a/MCUME_teensy41/teensylogo/tft_t_dma_config.h +++ /dev/null @@ -1,13 +0,0 @@ -#include "platform_config.h" - -//#define ST7789 1 -//#define ILI9341 1 - -#define TFT_LINEARINT 1 -#define LINEARINT_HACK 1 - -//#define FLIP_SCREEN 1 -//#define TFT_DEBUG 1 -#if defined(__IMXRT1052__) || defined(__IMXRT1062__) -#define TFT_STATICFB 1 -#endif diff --git a/MCUME_teensy41/teensylogo/vga_t_dma.h b/MCUME_teensy41/teensylogo/vga_t_dma.h deleted file mode 100644 index 81a986b..0000000 --- a/MCUME_teensy41/teensylogo/vga_t_dma.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - Wrapping class to extend VGA_T4 to TFT_T_DMA -*/ - -#ifndef _VGA_T_DMAH_ -#define _VGA_T_DMAH_ - -#ifdef __cplusplus -#include -#endif - - -#define RGBVAL16(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) - - - - -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 - -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - - - -#ifdef __cplusplus - -class TFT_T_DMA: public VGA_T4 -{ - public: - // Fake touch screen functions - bool isTouching(void) { return false; } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { } - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { }; - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { } - - // fake DMA functions - void startDMA(void) { }; - void stopDMA(void) { }; - - // fake no DMA functions - void writeScreenNoDma(const vga_pixel *pcolors) { writeScreen(pcolors); } - void fillScreenNoDma(vga_pixel color) { clear(color); } - void drawTextNoDma(int16_t x, int16_t y, const char * text, vga_pixel fgcolor, vga_pixel bgcolor, bool doublesize) { drawText(x,y,text,fgcolor,bgcolor,doublesize); } - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, vga_pixel color) { drawRect(x, y, w, h, color); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap) { drawSprite(x, y, bitmap); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh) { drawSprite(x, y, bitmap, croparx, cropary, croparw, croparh); } -}; - - -#endif -#endif diff --git a/MCUME_teensy41/teensymsx/.DS_Store b/MCUME_teensy41/teensymsx/.DS_Store deleted file mode 100644 index 0ff36a9..0000000 Binary files a/MCUME_teensy41/teensymsx/.DS_Store and /dev/null differ diff --git a/MCUME_teensy41/teensymsx/AudioPlaySystem.cpp b/MCUME_teensy41/teensymsx/AudioPlaySystem.cpp index dff01de..85da04d 100644 --- a/MCUME_teensy41/teensymsx/AudioPlaySystem.cpp +++ b/MCUME_teensy41/teensymsx/AudioPlaySystem.cpp @@ -176,7 +176,6 @@ void AudioPlaySystem::step(void) { } -#ifndef HAS_T4_VGA /******************************************************************* Experimental I2S interrupt based sound driver for PCM51xx !!! *******************************************************************/ @@ -263,7 +262,57 @@ FLASHMEM static void config_sai1() I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE ;//<-- not using DMA */; } +FLASHMEM static void config_pt8211() +{ + CCM_CCGR5 |= CCM_CCGR5_SAI1(CCM_CCGR_ON); + double fs = AUDIO_SAMPLE_RATE_EXACT; + // PLL between 27*24 = 648MHz und 54*24=1296MHz + int n1 = 4; //SAI prescaler 4 => (n1*n2) = multiple of 4 + int n2 = 1 + (24000000 * 27) / (fs * 256 * n1); + double C = (fs * 256 * n1 * n2) / 24000000; + int c0 = C; + int c2 = 10000; + int c1 = C * c2 - (c0 * c2); + set_audioClock(c0, c1, c2, true); + // clear SAI1_CLK register locations + CCM_CSCMR1 = (CCM_CSCMR1 & ~(CCM_CSCMR1_SAI1_CLK_SEL_MASK)) + | CCM_CSCMR1_SAI1_CLK_SEL(2); // &0x03 // (0,1,2): PLL3PFD0, PLL5, PLL4 + + //n1 = n1 / 2; //Double Speed for TDM + + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_SAI1_CLK_PRED_MASK | CCM_CS1CDR_SAI1_CLK_PODF_MASK)) + | CCM_CS1CDR_SAI1_CLK_PRED(n1 - 1) // &0x07 + | CCM_CS1CDR_SAI1_CLK_PODF(n2 - 1); // &0x3f + + IOMUXC_GPR_GPR1 = (IOMUXC_GPR_GPR1 & ~(IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL_MASK)) + | (IOMUXC_GPR_GPR1_SAI1_MCLK_DIR | IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL(0)); //Select MCLK + + + // configure transmitter + int rsync = 0; + int tsync = 1; + + I2S1_TMR = 0; + I2S1_TCR1 = I2S_TCR1_RFW(0); + I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_BCP | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(1); + I2S1_TCR3 = I2S_TCR3_TCE; + I2S1_TCR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(15) | I2S_TCR4_MF | I2S_TCR4_FSD /*| I2S_TCR4_FSE*/ | I2S_TCR4_FSP ; //PT8211 + I2S1_TCR5 = I2S_TCR5_WNW(15) | I2S_TCR5_W0W(15) | I2S_TCR5_FBT(15); + + I2S1_RMR = 0; + I2S1_RCR1 = I2S_RCR1_RFW(0); + I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_RCR2_BCP | I2S_RCR2_MSEL(1)| I2S_RCR2_BCD | I2S_RCR2_DIV(1) ; + I2S1_RCR3 = I2S_RCR3_RCE; + I2S1_RCR4 = I2S_RCR4_FRSZ(1) | I2S_RCR4_SYWD(15) | I2S_RCR4_MF /*| I2S_RCR4_FSE*/ | I2S_RCR4_FSP | I2S_RCR4_FSD; //PT8211 + I2S1_RCR5 = I2S_RCR5_WNW(15) | I2S_RCR5_W0W(15) | I2S_RCR5_FBT(15); + + CORE_PIN21_CONFIG = 3; // RX_BCLK + CORE_PIN20_CONFIG = 3; // RX_SYNC + CORE_PIN7_CONFIG = 3; // TX_DATA0 + I2S1_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE; + I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE ;//<-- not using DMA */; +} //DMAMEM __attribute__((aligned(32))) static uint32_t i2s_tx[1024]; @@ -277,7 +326,6 @@ static uint32_t * i2s_tx_buffer __attribute__((aligned(32))); static uint16_t * i2s_tx_buffer16; static uint16_t * txreg = (uint16_t *)((uint32_t)&I2S1_TDR0 + 2); - FASTRUN void AudioPlaySystem::AUDIO_isr() { *txreg = i2s_tx_buffer16[cnt]; @@ -335,7 +383,14 @@ FLASHMEM void AudioPlaySystem::begin_audio(int samplesize, void (*callback)(shor sampleBufferSize = samplesize; +#ifdef PT8211 + txreg = (uint16_t *)((uint32_t)&I2S1_TDR0); + config_pt8211(); +#else + txreg = (uint16_t *)((uint32_t)&I2S1_TDR0 + 2); config_sai1(); +#endif + attachInterruptVector(IRQ_SAI1, AUDIO_isr); NVIC_ENABLE_IRQ(IRQ_SAI1); NVIC_SET_PRIORITY(IRQ_QTIMER3, 0); // 0 highest priority, 255 = lowest priority @@ -358,4 +413,3 @@ FLASHMEM void AudioPlaySystem::end_audio() } #endif -#endif diff --git a/MCUME_teensy41/teensymsx/AudioPlaySystem.h b/MCUME_teensy41/teensymsx/AudioPlaySystem.h index fb22cdc..6d2e23b 100644 --- a/MCUME_teensy41/teensymsx/AudioPlaySystem.h +++ b/MCUME_teensy41/teensymsx/AudioPlaySystem.h @@ -19,13 +19,10 @@ public: void buzz(int size, int val); void step(void); static void snd_Mixer(short * stream, int len ); -#ifndef HAS_T4_VGA void begin_audio(int samplesize, void (*callback)(short * stream, int len)); void end_audio(); static void AUDIO_isr(void); - static void SOFTWARE_isr(void); -#endif - + static void SOFTWARE_isr(void); }; diff --git a/MCUME_teensy41/teensymsx/Boot.c b/MCUME_teensy41/teensymsx/Bootblock.c similarity index 98% rename from MCUME_teensy41/teensymsx/Boot.c rename to MCUME_teensy41/teensymsx/Bootblock.c index 26b0cd1..b354976 100644 --- a/MCUME_teensy41/teensymsx/Boot.c +++ b/MCUME_teensy41/teensymsx/Bootblock.c @@ -1,6 +1,6 @@ /** fMSX: portable MSX emulator ******************************/ /** **/ -/** Boot.h **/ +/** Bootblock.h **/ /** **/ /** This file contains MSX boot sector image used to create **/ /** new disk images during FORMAT operation. **/ diff --git a/MCUME_teensy41/teensymsx/Boot.h b/MCUME_teensy41/teensymsx/Bootblock.h similarity index 91% rename from MCUME_teensy41/teensymsx/Boot.h rename to MCUME_teensy41/teensymsx/Bootblock.h index f2e883a..d9092f2 100644 --- a/MCUME_teensy41/teensymsx/Boot.h +++ b/MCUME_teensy41/teensymsx/Bootblock.h @@ -1,6 +1,6 @@ /** fMSX: portable MSX emulator ******************************/ /** **/ -/** Boot.h **/ +/** Bootblock.h **/ /** **/ /** This file contains MSX boot sector image used to create **/ /** new disk images during FORMAT operation. **/ diff --git a/MCUME_teensy41/teensymsx/Patch.c b/MCUME_teensy41/teensymsx/Patch.c index 5786a71..5e3f1e8 100644 --- a/MCUME_teensy41/teensymsx/Patch.c +++ b/MCUME_teensy41/teensymsx/Patch.c @@ -12,7 +12,7 @@ /*************************************************************/ #include "MSX.h" -#include "Boot.h" +#include "Bootblock.h" #include #include #include @@ -29,7 +29,7 @@ void SSlot(byte Value); /* Used to switch secondary slots */ #ifdef FMSX extern byte *RAM[],PSL[],SSLReg; -static byte RdZ80(word A) +static byte RdZ80(WORD A) { if(A!=0xFFFF) return(RAM[A>>13][A&0x1FFF]); else return((PSL[3]==3)? ~SSLReg:RAM[7][0x1FFF]); @@ -60,7 +60,7 @@ void PatchZ80(Z80 *R) byte Buf[512],Count,PS,SS,N,*P; int J,I,Sector; - word Addr; + WORD Addr; switch(R->PC.W-2) { diff --git a/MCUME_teensy41/teensymsx/Sound.h b/MCUME_teensy41/teensymsx/Sound.h index 9103ca5..d3ec6fc 100644 --- a/MCUME_teensy41/teensymsx/Sound.h +++ b/MCUME_teensy41/teensymsx/Sound.h @@ -149,4 +149,3 @@ struct SndDriverStruct extern struct SndDriverStruct SndDriver; #endif /* SOUND_H */ - diff --git a/MCUME_teensy41/teensymsx/Tables.h b/MCUME_teensy41/teensymsx/Tables.h index c08e9a0..2b5e27b 100644 --- a/MCUME_teensy41/teensymsx/Tables.h +++ b/MCUME_teensy41/teensymsx/Tables.h @@ -186,7 +186,7 @@ static const byte PZSTable[256] = S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG }; -static const word DAATable[2048] = +static const WORD DAATable[2048] = { 0x0044,0x0100,0x0200,0x0304,0x0400,0x0504,0x0604,0x0700, 0x0808,0x090C,0x1010,0x1114,0x1214,0x1310,0x1414,0x1510, diff --git a/MCUME_teensy41/teensymsx/Z80.c b/MCUME_teensy41/teensymsx/Z80.c index bb828d0..3eeee1b 100644 --- a/MCUME_teensy41/teensymsx/Z80.c +++ b/MCUME_teensy41/teensymsx/Z80.c @@ -33,15 +33,15 @@ /*************************************************************/ #ifdef COLEM extern byte *Page[]; -INLINE byte RdZ80(word A) { return(Page[A>>15][A&0x7FFF]); } +INLINE byte RdZ80(WORD A) { return(Page[A>>15][A&0x7FFF]); } #endif #ifdef MG extern byte *Page[]; -INLINE byte RdZ80(word A) { return(Page[A>>13][A&0x1FFF]); } +INLINE byte RdZ80(WORD A) { return(Page[A>>13][A&0x1FFF]); } #endif #ifdef FMSX extern byte *RAM[],PSL[],SSLReg; -INLINE byte RdZ80(word A) +INLINE byte RdZ80(WORD A) { if(A!=0xFFFF) return(RAM[A>>13][A&0x1FFF]); else return((PSL[3]==3)? ~SSLReg:RAM[7][0x1FFF]); @@ -478,7 +478,7 @@ void ResetZ80(Z80 *R) /** This function will execute a single Z80 opcode. It will **/ /** then return next PC, and current register values in R. **/ /*************************************************************/ -word ExecZ80(Z80 *R) +WORD ExecZ80(Z80 *R) { register byte I; register pair J; @@ -501,7 +501,7 @@ word ExecZ80(Z80 *R) /** IntZ80() *************************************************/ /** This function will generate interrupt of given vector. **/ /*************************************************************/ -void IntZ80(Z80 *R,word Vector) +void IntZ80(Z80 *R,WORD Vector) { if((R->IFF&IFF_1)||(Vector==INT_NMI)) { @@ -534,7 +534,7 @@ void IntZ80(Z80 *R,word Vector) if(R->IFF&IFF_IM2) { /* Make up the vector address */ - Vector=(Vector&0xFF)|((word)(R->I)<<8); + Vector=(Vector&0xFF)|((WORD)(R->I)<<8); /* Read the vector */ R->PC.B.l=RdZ80(Vector++); R->PC.B.h=RdZ80(Vector); @@ -567,7 +567,7 @@ void IntZ80(Z80 *R,word Vector) /** returns INT_QUIT. It will return the PC at which **/ /** emulation stopped, and current register values in R. **/ /*************************************************************/ -word RunZ80(Z80 *R) +WORD RunZ80(Z80 *R) { register byte I; register pair J; diff --git a/MCUME_teensy41/teensymsx/Z80.h b/MCUME_teensy41/teensymsx/Z80.h index 2f1f0ea..670faef 100644 --- a/MCUME_teensy41/teensymsx/Z80.h +++ b/MCUME_teensy41/teensymsx/Z80.h @@ -50,7 +50,7 @@ #define IFF_HALT 0x80 /* 1: CPU HALTed */ /** Simple Datatypes *****************************************/ -/** NOTICE: sizeof(byte)=1 and sizeof(word)=2 **/ +/** NOTICE: sizeof(byte)=1 and sizeof(WORD)=2 **/ /*************************************************************/ #ifndef BYTE_TYPE_DEFINED #define BYTE_TYPE_DEFINED @@ -58,8 +58,8 @@ typedef unsigned char byte; #endif #ifndef WORD_TYPE_DEFINED #define WORD_TYPE_DEFINED -#ifndef word -typedef unsigned short word; +#ifndef WORD +typedef unsigned short WORD; #endif #endif typedef signed char offset; @@ -75,7 +75,7 @@ typedef union #else struct { byte h,l; } B; #endif - word W; + WORD W; } pair; typedef struct @@ -88,10 +88,10 @@ typedef struct int IPeriod,ICount; /* Set IPeriod to number of CPU cycles */ /* between calls to LoopZ80() */ int IBackup; /* Private, don't touch */ - word IRequest; /* Set to address of pending IRQ */ + WORD IRequest; /* Set to address of pending IRQ */ byte IAutoReset; /* Set to 1 to autom. reset IRequest */ byte TrapBadOps; /* Set to 1 to warn of illegal opcodes */ - word Trap; /* Set Trap to address to trace from */ + WORD Trap; /* Set Trap to address to trace from */ byte Trace; /* Set Trace=1 to start tracing */ void *User; /* Arbitrary user data (ID,RAM*,etc.) */ } Z80; @@ -107,34 +107,34 @@ void ResetZ80(register Z80 *R); /** This function will execute a single Z80 opcode. It will **/ /** then return next PC, and current register values in R. **/ /*************************************************************/ -word ExecZ80(register Z80 *R); +WORD ExecZ80(register Z80 *R); /** IntZ80() *************************************************/ /** This function will generate interrupt of given vector. **/ /*************************************************************/ -void IntZ80(register Z80 *R,register word Vector); +void IntZ80(register Z80 *R,register WORD Vector); /** RunZ80() *************************************************/ /** This function will run Z80 code until an LoopZ80() call **/ /** returns INT_QUIT. It will return the PC at which **/ /** emulation stopped, and current register values in R. **/ /*************************************************************/ -word RunZ80(register Z80 *R); +WORD RunZ80(register Z80 *R); /** RdZ80()/WrZ80() ******************************************/ /** These functions are called when access to RAM occurs. **/ /** They allow to control memory access. **/ /************************************ TO BE WRITTEN BY USER **/ -void WrZ80(register word Addr,register byte Value); -byte RdZ80(register word Addr); +void WrZ80(register WORD Addr,register byte Value); +byte RdZ80(register WORD Addr); /** InZ80()/OutZ80() *****************************************/ /** Z80 emulation calls these functions to read/write from **/ /** I/O ports. There can be 65536 I/O ports, but only first **/ /** 256 are usually used. **/ /************************************ TO BE WRITTEN BY USER **/ -void OutZ80(register word Port,register byte Value); -byte InZ80(register word Port); +void OutZ80(register WORD Port,register byte Value); +byte InZ80(register WORD Port); /** PatchZ80() ***********************************************/ /** Z80 emulation calls this function when it encounters a **/ @@ -162,6 +162,6 @@ byte DebugZ80(register Z80 *R); /** (0x0038, 0x0066, etc.) or INT_NONE for no interrupt. **/ /** Return INT_QUIT to exit the emulation loop. **/ /************************************ TO BE WRITTEN BY USER **/ -word LoopZ80(register Z80 *R, int * ras); +WORD LoopZ80(register Z80 *R, int * ras); #endif /* Z80_H */ diff --git a/MCUME_teensy41/teensymsx/emuapi.cpp b/MCUME_teensy41/teensymsx/emuapi.cpp index c367cb0..e128cca 100644 --- a/MCUME_teensy41/teensymsx/emuapi.cpp +++ b/MCUME_teensy41/teensymsx/emuapi.cpp @@ -5,25 +5,31 @@ extern "C" { #include "iopins.h" } -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#else -#include "tft_t_dma.h" -#endif +#include -#ifdef HAS_USBKEY +#ifdef HAS_USB #include "USBHost_t36.h" // Read this header first for key info USBHost myusb; USBHub hub1(myusb); +#ifdef HAS_USBKEY KeyboardController keyboard1(myusb); USBHIDParser hid1(myusb); MouseController mouse1(myusb); +#endif +#ifdef HAS_USBMIDI MIDIDevice midi1(myusb); #endif +#ifdef HAS_USBJOY +#define COUNT_JOYSTICKS 4 +JoystickController joysticks[COUNT_JOYSTICKS](myusb); +#endif +#endif static bool emu_writeConfig(void); static bool emu_readConfig(void); static bool emu_eraseConfig(void); +static bool emu_writeGfxConfig(char * display_type); +static int emu_readGfxConfig(void); static bool mouseDetected = false; static bool keyboardDetected = false; @@ -34,12 +40,13 @@ static File file; #define MAX_FILES 64 #define AUTORUN_FILENAME "autorun.txt" +#define GFX_CFG_FILENAME "gfxmode.txt" -#define MAX_FILENAME_SIZE 24 +#define MAX_FILENAME_SIZE 34 #define MAX_MENULINES 9 #define TEXT_HEIGHT 16 #define TEXT_WIDTH 8 -#define MENU_FILE_XOFFSET (6*TEXT_WIDTH) +#define MENU_FILE_XOFFSET (2*TEXT_WIDTH) #define MENU_FILE_YOFFSET (2*TEXT_HEIGHT) #define MENU_FILE_W (MAX_FILENAME_SIZE*TEXT_WIDTH) #define MENU_FILE_H (MAX_MENULINES*TEXT_HEIGHT) @@ -53,7 +60,8 @@ static File file; #define MENU_VGA_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) #define MENU_VGA_YOFFSET (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37) -extern TFT_T_DMA tft; +#include "t4_dsp.h" +T4_DSP tft; static int nbFiles=0; static int curFile=0; @@ -65,6 +73,8 @@ static char selected_filename[MAX_FILENAME_SIZE]=""; static char second_selected_filename[MAX_FILENAME_SIZE]=""; static bool menuRedraw=true; static bool autorun=false; +static bool vgahires=false; + static const unsigned short * keys; #ifdef TEECOMPUTER @@ -158,6 +168,29 @@ void emu_Free(void * pt) free(pt); } +#define SMEMPOOL (0x800000) +EXTMEM static unsigned char slowmem[SMEMPOOL]; +static int slowmempt = 0; + +void * emu_SMalloc(unsigned int size) +{ + void * mem = (void*)&slowmem[slowmempt]; + slowmempt += size; + + if ( slowmempt > SMEMPOOL ) { + mem = NULL; + emu_printf("failure to allocate slow"); + } + else { + emu_printf("could allocate slow static "); + emu_printf(size); + } + return mem; +} + +void emu_SFree(void * pt) +{ +} /******************************** * Input and keyboard ********************************/ @@ -329,6 +362,12 @@ int emu_ReadKeys(void) #endif if ( row & 0x02 ) retval |= MASK_JOY2_BTN; + +#ifdef EXTPAD + if ( sh_pressed ) retval |= MASK_KEY_USER3; + if ( fn_pressed ) retval |= MASK_KEY_USER1; + digitalWrite(KLED, 0); +#else // Handle LED flash uint32_t time_ms=millis(); if ((time_ms-last_t_ms) > 100) { @@ -412,8 +451,9 @@ int emu_ReadKeys(void) if ( key_fn ) retval |= MASK_KEY_USER2; if ( ( key_fn ) && (keymatrix[4] == 0x10 )) retval |= MASK_KEY_USER1; +#endif - if ( (key_fn) && (key_sh) ) + if ( (fn_pressed) && (sh_pressed) ) #else if ( ((retval & (MASK_KEY_USER1+MASK_KEY_USER2)) == (MASK_KEY_USER1+MASK_KEY_USER2)) || (retval & MASK_KEY_USER4 ) ) @@ -453,8 +493,10 @@ int emu_ReadKeys(void) while (true) { ; } -#endif +#endif } + + emu_GetJoystick(); return (retval); } @@ -607,7 +649,7 @@ int emu_setKeymap(int index) { } int emu_GetMouse(int *x, int *y, int *buts) { -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBKEY) if (mouse1.available()) { *buts = mouse1.getButtons(); *x = mouse1.getMouseX(); @@ -620,7 +662,23 @@ int emu_GetMouse(int *x, int *y, int *buts) { return 0; } -#ifdef HAS_USBKEY +int emu_GetJoystick(void) { +#if defined(HAS_USB) && (HAS_USBJOY) + for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) { + if (joysticks[joystick_index].available()) { + uint64_t axis_mask = joysticks[joystick_index].axisMask(); + uint64_t axis_changed_mask = joysticks[joystick_index].axisChangedMask(); + uint32_t buttons = joysticks[joystick_index].getButtons(); + Serial.printf("Joystick(%d): buttons = %x", joystick_index, buttons); + Serial.println(); + } + } + return 1; +#endif + return 0; +} + +#if defined(HAS_USB) && (HAS_USBKEY) void OnPress(auto key) { keyboardDetected = true; @@ -764,7 +822,7 @@ int emu_KeyboardDetected(void) { return (keyboardDetected?1:0); } -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) static unsigned char midiBuffer[16]; static unsigned char midiLastCmd=0; static int midiDataCnt=0; @@ -772,8 +830,7 @@ static int midiCmdNbParam=0; #endif void emu_MidiOnDataReceived(unsigned char value) { - -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) //Serial.println(value, HEX); //10000000 = 128 = note off //10010000 = 144 = note on @@ -941,6 +998,7 @@ void emu_MidiOnDataReceived(unsigned char value) { /******************************** * Menu file loader UI ********************************/ +#ifdef FILEBROWSER static int readNbFiles(void) { int totalFiles = 0; @@ -970,8 +1028,6 @@ static int readNbFiles(void) { return totalFiles; } - - void backgroundMenu(void) { menuRedraw=true; tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00)); @@ -981,11 +1037,13 @@ void backgroundMenu(void) { int handleMenu(uint16_t bClick) { if (autorun) { + toggleMenu(false); + menuRedraw=false; return (ACTION_RUN1); } int action = ACTION_NONE; - if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) ) { + if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) || ( bClick & MASK_KEY_USER2 ) ) { char newpath[MAX_FILENAME_PATH]; strcpy(newpath, selection); strcat(newpath, "/"); @@ -996,17 +1054,31 @@ int handleMenu(uint16_t bClick) File file = SD.open(selection); if (file.isDirectory()) { curFile = 0; - nbFiles = readNbFiles(); + nbFiles = readNbFiles(); + menuRedraw=true; } - else { - action = ACTION_RUN1; + else + { #ifdef TEECOMPUTER - if (key_extmode) { + if ( (key_extmode) || ( key_sh) ) { emu_writeConfig(); } + if ( tft.getMode() < MODE_VGA_320x240) { + if ( bClick & MASK_KEY_USER2 ) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + } + //emu_SwapJoysticks(0); #endif + toggleMenu(false); + menuRedraw=false; + return (ACTION_RUN1); } - menuRedraw=true; } else if ( bClick & MASK_KEY_USER1 ) { menuRedraw=true; @@ -1015,19 +1087,14 @@ int handleMenu(uint16_t bClick) strcat(second_selection, "/"); strcat(second_selection, second_selected_filename); action = ACTION_RUN2; - } - else if ( bClick & MASK_KEY_USER2 ) { - menuRedraw=true; - //action = ACTION_RUN3; - emu_SwapJoysticks(0); - } + } else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) { if (curFile!=0) { menuRedraw=true; curFile--; } } - else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { + else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { if ((curFile-9)>=0) { menuRedraw=true; curFile -= 9; @@ -1042,7 +1109,7 @@ int handleMenu(uint16_t bClick) menuRedraw=true; } } - else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { + else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { if ((curFile<(nbFiles-9)) && (nbFiles)) { curFile += 9; menuRedraw=true; @@ -1099,12 +1166,12 @@ int handleMenu(uint16_t bClick) return (action); } -bool menuActive(void) +int menuActive(void) { - return (menuOn); + return (menuOn?1:0); } -void toggleMenu(bool on) { +void toggleMenu(int on) { if (on) { menuOn=true; backgroundMenu(); @@ -1122,7 +1189,7 @@ char * menuSecondSelection(void) { return (second_selection); } - +#endif /******************************** * OSKB handling @@ -1140,8 +1207,9 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) char c[4] = {' ',0,' ',0}; const char * cpt = str; int i=0; - int fb_width,fb_height; - tft.get_frame_buffer_size(&fb_width, &fb_height); + int fb_width,fb_height,fbstride; + + fbstride = tft.get_frame_buffer_size(&fb_width, &fb_height); int ypos = (bottom?(fb_height-2*8):0); int line = row + (bottom?2:0); while ((c[1] = *cpt++)) @@ -1150,7 +1218,7 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0); else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff); if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff); - tft.drawTextNoDma(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); + tft.drawText(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); i++; } } @@ -1248,7 +1316,7 @@ int handleOSKB(void) { return retval; } -void toggleOSKB(bool forceon) { +void toggleOSKB(int forceon) { if (forceon) { oskbOn = true; drawOSKB(); @@ -1332,6 +1400,17 @@ int emu_FileRead(void * buf, int size, int handler) #endif } +int emu_FileWrite(void * buf, int size, int handler) +{ +// emu_printf("emu_FileWrite"); +// emu_printi(handler); +#ifdef HCFH + return (file.write(buf, size)); +#else + return (getFileHandler(handler).write(buf, size)); +#endif +} + int emu_FileGetc(int handler) { // emu_printf("FileGetc"); // emu_printi(handler); @@ -1404,6 +1483,9 @@ unsigned int emu_FileSize(const char * filepath) emu_printf(filesize); lofile.close(); } + else { + emu_printf("filesize failed"); + } return(filesize); } @@ -1489,6 +1571,48 @@ static bool emu_eraseConfig(void) SD.remove (ROMSDIR "/" AUTORUN_FILENAME); } +static bool emu_writeGfxConfig(char * display_type) +{ + bool retval = false; + SD.remove ("/" GFX_CFG_FILENAME); + if (strcmp(display_type, "VGA")) { + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(display_type, strlen(display_type)) != strlen(display_type)) { + emu_printf("GFX config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + } + return retval; +} + +#define CFG_VGA 0 +#define CFG_ILI 1 +#define CFG_ST 2 + +static int emu_readGfxConfig(void) +{ + int retval = CFG_VGA; // No file = VGA + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + if (filesize == 2) // "ST" + { + retval = CFG_ST; + } + else if (filesize == 3) // "ILI" + { + retval = CFG_ILI; + } + lofile.close(); + } + return retval; +} + /******************************** * File IO compatibility ********************************/ @@ -1670,62 +1794,249 @@ FRESULT f_mkdir (const char* path) /******************************** - * Initialization + * GFX wrapper ********************************/ -void emu_init(void) +static unsigned short palette16[PALETTE_SIZE]; +static IntervalTimer myTimer; +volatile boolean vbl=true; +volatile boolean vgatimervsync=false; +static void (*vblCallback)(void) = nullptr; +static int skip=0; + +static void vblCount() { + if (vbl) { + vbl = false; + } else { + vbl = true; + } +} + +void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) +{ + if (index= MODE_VGA_320x240 ) { + if (vgatimervsync) { + while (vbl==vb) {}; + } + else { + tft.waitSync(); + } + } + else { + while (vbl==vb) {}; + } + if (vblCallback != nullptr) { + vblCallback(); + } +} + +void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride) +{ + if (skip == 0) { + tft.writeScreenPal(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); + } +} +void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLinePal(width,height,line, VBuf, palette16); + } +} + +void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine(width,height,line, VBuf); + } +} + +void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine8(width,height,line, VBuf, palette16); + } +} + +int emu_IsVga(void) +{ + return (tft.getMode() >= MODE_VGA_320x240?1:0); +} + +int emu_IsVgaHires(void) +{ + return (tft.getMode() >= MODE_VGA_640x240?1:0); +} + +int emu_FrameSkip(void) +{ + return skip; +} + + +/******************************** + * AUDIO wrapper +********************************/ +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +AudioPlaySystem mymixer; + +void emu_sndInit() { + Serial.println("sound init"); + mymixer.begin_audio(256, mymixer.snd_Mixer); + mymixer.start(); +} + +void emu_sndPlaySound(int chan, int volume, int freq) +{ + if (chan < 6) { + mymixer.sound(chan, freq, volume); + } + /* + Serial.print(chan); + Serial.print(":" ); + Serial.print(volume); + Serial.print(":" ); + Serial.println(freq); + */ +} + +void emu_sndPlayBuzz(int size, int val) { + mymixer.buzz(size,val); + //Serial.print((val==1)?1:0); + //Serial.print(":"); + //Serial.println(size); +} +#endif + +/******************************** + * Initialization +********************************/ +void emu_init(int hires) { Serial.begin(115200); + vgahires = hires; -#ifdef HAS_USBKEY +#ifdef HAS_USB myusb.begin(); +#ifdef HAS_USBKEY keyboard1.attachPress(OnPress); keyboard1.attachRelease(OnRelease); #endif +#endif - while (!SD.begin(SD_CS)) +#ifdef FILEBROWSER + if (!SD.begin(SD_CS)) { - Serial.println("SD begin failed, retrying..."); - delay(1000); + Serial.println("No SD card detected"); } strcpy(selection,ROMSDIR); - FileHandlersInit(); - nbFiles = readNbFiles(); - - Serial.print("SD initialized, files found: "); Serial.println(nbFiles); +#endif emu_InitJoysticks(); #ifdef SWAP_JOYSTICK - joySwapped = true; + joySwapped = true; #else - joySwapped = false; + joySwapped = false; #endif -#ifdef TEECOMPUTER -#ifndef HAS_T4_VGA - tft.flipscreen(false); -#endif -#endif int keypressed = emu_ReadKeys(); +#ifdef HAS_T4_VGA + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } +#else + int gfx_mode = CFG_VGA; // default +#ifdef FILEBROWSER + gfx_mode = emu_readGfxConfig(); +#endif + // Force VGA if UP pressed + if (keypressed & MASK_JOY2_UP) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("VGA"); +#endif + gfx_mode = CFG_VGA; + } + else { + if (keypressed & MASK_JOY2_LEFT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ST"); +#endif + gfx_mode = CFG_ST; + } + else if (keypressed & MASK_JOY2_RIGHT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ILI"); +#endif + gfx_mode = CFG_ILI; + } + } + if (gfx_mode == CFG_VGA) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + else + { + tft.begin(gfx_mode == CFG_ILI?MODE_TFTILI_320x240:MODE_TFTST_320x240); + } +#endif + if (keypressed & MASK_JOY2_DOWN) { tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) ); tft.drawTextNoDma(64,48, (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); +#ifdef FILEBROWSER emu_eraseConfig(); delay(1000); +#endif } else { +#ifdef FILEBROWSER if (emu_readConfig()) { autorun = true; } +#endif } +#ifdef FILEBROWSER toggleMenu(true); +#endif } -void emu_start(void) +void emu_start(int vblms, void * callback, int forcetimervsync) { + vgatimervsync = forcetimervsync?true:false; + tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); + tft.startRefresh(); + if (callback != nullptr) { + vblCallback = callback; + } + + myTimer.begin(vblCount, vblms); +#ifdef HAS_SND + emu_sndInit(); +#endif usbnavpad = 0; } diff --git a/MCUME_teensy41/teensymsx/emuapi.h b/MCUME_teensy41/teensymsx/emuapi.h index 6c5d232..5dd6130 100644 --- a/MCUME_teensy41/teensymsx/emuapi.h +++ b/MCUME_teensy41/teensymsx/emuapi.h @@ -2,134 +2,14 @@ #define EMUAPI_H #include "platform_config.h" - -#define CUSTOM_SND 1 -//#define TIMER_REND 1 - -#define EXTRA_HEAP 0x30000 - -// Title: < > -#define TITLE " MSX Emulator " -#define ROMSDIR "/msx" - -#define emu_Init(ROM) {msx_Init(); msx_Start(ROM);} -#define emu_Step(x) {msx_Step();} -#define emu_Input(x) {msx_Input(x);} - -#define MAX_FILENAME_PATH 64 -#define NB_FILE_HANDLER 4 -#define PALETTE_SIZE 256 -#define VID_FRAME_SKIP 0x0 -#define TFT_VBUFFER_YCROP 0 -#define SINGLELINE_RENDERING 1 - -#define R32(rgb) ((rgb>>16)&0xff) -#define G32(rgb) ((rgb>>8)&0xff) -#define B32(rgb) (rgb & 0xff) +#include "emucfg.h" #define ACTION_NONE 0 -#define ACTION_MAXKBDVAL 16 -#define ACTION_EXITKBD 128 -#define ACTION_RUN1 129 -#define ACTION_RUN2 130 -#define ACTION_RUN3 131 - - -#ifdef KEYMAP_PRESENT - -/* -const unsigned short key_map1[]={ - -1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -11, 12, 13, 14, 15, 16, 17, 18, 19, 20, -21, 22, 23, 24, 25, 26, 27, 28, 29, 30, -31, 32, 33, 34, 35, 36, 37, 38, 39, 40 }; -*/ -#define keylables_map0_0 (char *)"qwertyuiop\x1a" -#define keylables_map0_1 (char *)" asdfghjkl\x19" -#define keylables_map0_2 (char *)" zxcvbnm,.;/" -#define keylables_map0_3 (char *)" +\x10-" -const unsigned short key_map0[] = { - 'q','w','e','r','t','y','u','i','o','p',127, //lowecase - 0,'a','s','d','f','g','h','j','k','l',10, - 0,'z','x','c','v','b','n','m',',','.',';','/', - 0,0,0,0, //U L R D - 0,'+',' ','-' - }; - -#define keylables_map1_0 (char *)"1234567890 " -#define keylables_map1_1 (char *)" " -#define keylables_map1_2 (char *)" " -#define keylables_map1_3 (char *)" " - -const unsigned short key_map1[] = { - '1','2','3','4','5','6','7','8','9','0',0, // digit keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map2_0 (char *)"!\"#$%^&*()@" -#define keylables_map2_1 (char *)" " -#define keylables_map2_2 (char *)" <>:?" -#define keylables_map2_3 (char *)" =\x10_" -const unsigned short key_map2[] = { - '!','"','#','$','%','^','&','*','(',')','@', // shiftothers - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,'<','>',':','?', - 153,151,150,152, //U L R D - 0,'=',' ','_' - }; - -#define keylables_map3_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " -#define keylables_map3_1 (char *)" " -#define keylables_map3_2 (char *)" " -#define keylables_map3_3 (char *)" " - -const unsigned short key_map3[] = { - 129,130,131,132,133,134,135,136,0,0,0, // function keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map4_0 (char *)"QWERTYUIOP@" -#define keylables_map4_1 (char *)" ASDFGHJKL\x19" -#define keylables_map4_2 (char *)" ZXCVBNM<>:?" -#define keylables_map4_3 (char *)" =\x10_" -const unsigned short key_map4[] = { - 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase - 0,'A','S','D','F','G','H','J','K','L',10, - 0,'Z','X','C','V','B','N','M','<','>',':','?', - 0,0,0,0, - 0,'=',' ','_' - }; - -#define keylables_map5_0 (char *)" " -#define keylables_map5_1 (char *)" " -#define keylables_map5_2 (char *)" " -#define keylables_map5_3 (char *)" " - -const unsigned short key_map5[] = { - 0,0,0,0,0,0,0,0,0,0,0, // extra keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 153,151,150,152, //U L R D - 0,0,' ',0 - }; - -const unsigned short matkeys[] = { - 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 - 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 - 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 - 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN - 0x510,0x010,0x110,0x310, // row 4 - }; - -#endif +#define ACTION_RUN1 1 +#define ACTION_RUN2 2 +#define FORCE_VGATIMERVSYNC 1 +#define SUPPORT_HIRES 1 #define MASK_JOY2_RIGHT 0x0001 #define MASK_JOY2_LEFT 0x0002 @@ -146,22 +26,25 @@ const unsigned short matkeys[] = { #define MASK_JOY1_BTN 0x1000 #define MASK_KEY_USER4 0x2000 +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) #ifdef __cplusplus extern "C" { +extern void emu_init(int hires=0); +extern void emu_start(int vblms, void * callback, int forcetimervsync=0); #endif - -extern void emu_init(void); -extern void emu_start(void); extern void emu_printf(const char * text); extern void emu_printi(int val); extern void emu_printh(int val); extern void * emu_Malloc(unsigned int size); extern void * emu_MallocI(unsigned int size); extern void emu_Free(void * pt); +extern void * emu_SMalloc(unsigned int size); +extern void emu_SFree(void * pt); extern int emu_FileOpen(const char * filepath, const char * mode); extern int emu_FileRead(void * buf, int size, int handler); +extern int emu_FileWrite(void * buf, int size, int handler); extern int emu_FileGetc(int handler); extern int emu_FileSeek(int handler, int seek, int origin); extern int emu_FileTell(int handler); @@ -172,24 +55,23 @@ extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size); extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek); extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index); -extern void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride); -extern void emu_DrawLine(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line); extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line); +extern void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride); extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line); -extern void emu_CopyLine(int width, int height, int ysrc, int ydst); extern void emu_DrawVsync(void); extern int emu_FrameSkip(void); -extern void * emu_LineBuffer(int line); -extern void emu_tweakVideo(int shiftdelta, int numdelta, int denomdelta); +extern int emu_IsVga(void); +extern int emu_IsVgaHires(void); -extern bool menuActive(void); +extern int menuActive(void); extern char * menuSelection(void); extern char * menuSecondSelection(void); -extern void toggleMenu(bool on); +extern void toggleMenu(int on); extern int handleMenu(unsigned short bClick); extern int handleOSKB(void); -extern void toggleOSKB(bool forceon); +extern void toggleOSKB(int forceon); extern void emu_InitJoysticks(void); extern int emu_SwapJoysticks(int statusOnly); @@ -198,6 +80,7 @@ extern int emu_ReadKeys(void); extern int emu_GetPad(void); extern int emu_GetMouse(int *x, int *y, int *buts); extern int emu_MouseDetected(void); +extern int emu_GetJoystick(void); extern int emu_KeyboardDetected(void); extern int emu_ReadAnalogJoyX(int min, int max); extern int emu_ReadAnalogJoyY(int min, int max); diff --git a/MCUME_teensy41/teensymsx/emucfg.h b/MCUME_teensy41/teensymsx/emucfg.h new file mode 100644 index 0000000..04a0eed --- /dev/null +++ b/MCUME_teensy41/teensymsx/emucfg.h @@ -0,0 +1,125 @@ +#ifndef EMUCFG_H +#define EMUCFG_H + +#include "wrapemu.h" + +// Title: < > +#define TITLE " MSX Emulator " +#define ROMSDIR "/msx" + +#define emu_Init(ROM) {msx_Init(); msx_Start(ROM);} +#define emu_Step(x) {msx_Step();} +#define emu_Input(x) {msx_Input(x);} + +#define MAX_FILENAME_PATH 64 +#define NB_FILE_HANDLER 4 + +#define PALETTE_SIZE 256 +#define VID_FRAME_SKIP 0x0 +#define TFT_VBUFFER_YCROP 0 +#define SINGLELINE_RENDERING 1 +#define CUSTOM_SND 1 +//#define TIMER_REND 1 +//#define EXTPAD 1 +#define EXTRA_HEAP 0x30000 +#define FILEBROWSER 1 + + +#ifdef KEYMAP_PRESENT + +/* +const unsigned short key_map1[]={ + +1, 2, 3, 4, 5, 6, 7, 8, 9, 10, +11, 12, 13, 14, 15, 16, 17, 18, 19, 20, +21, 22, 23, 24, 25, 26, 27, 28, 29, 30, +31, 32, 33, 34, 35, 36, 37, 38, 39, 40 }; +*/ +#define keylables_map0_0 (char *)"qwertyuiop\x1a" +#define keylables_map0_1 (char *)" asdfghjkl\x19" +#define keylables_map0_2 (char *)" zxcvbnm,.;/" +#define keylables_map0_3 (char *)" +\x10-" +const unsigned short key_map0[] = { + 0x0A +1,0x0B +1,0x0C +1,0x0D +1,0x0E +1,0x0F +1,0x10 +1,0x11 +1,0x12 +1,0x13 +1,0x26 +1, //lowecase + 0,0x14 +1,0x15 +1,0x16 +1,0x17 +1,0x18 +1,0x19 +1,0x1A +1,0x1B +1,0x1C +1,0x1D +1, + 0,0x1F +1,0x20 +1,0x21 +1,0x22 +1,0x23 +1,0x24 +1,0x25 +1,0x1E +1,0,0,0, + 0,0,0,0, //U L R D + 0,0,0x27 +1,0 + }; + +#define keylables_map1_0 (char *)"1234567890 " +#define keylables_map1_1 (char *)" " +#define keylables_map1_2 (char *)" " +#define keylables_map1_3 (char *)" " + +const unsigned short key_map1[] = { + 1+1,2+1,3+1,4+1,5+1,6+1,7+1,8+1,9+1,0+1,0, // digit keys +// '1','2','3','4','5','6','7','8','9','0',0, // digit keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map2_0 (char *)"!\"#$%^&*()@" +#define keylables_map2_1 (char *)" " +#define keylables_map2_2 (char *)" <>:?" +#define keylables_map2_3 (char *)" =\x10_" +const unsigned short key_map2[] = { +// '!','"','#','$','%','^','&','*','(',')','@', // shiftothers + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 0,0,0,0, + 0,0,0,0 + }; + +#define keylables_map3_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " +#define keylables_map3_1 (char *)" " +#define keylables_map3_2 (char *)" " +#define keylables_map3_3 (char *)" " + +const unsigned short key_map3[] = { + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,0,0 + }; + +#define keylables_map4_0 (char *)"QWERTYUIOP@" +#define keylables_map4_1 (char *)" ASDFGHJKL\x19" +#define keylables_map4_2 (char *)" ZXCVBNM<>:?" +#define keylables_map4_3 (char *)" =\x10_" +const unsigned short key_map4[] = { + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,0,0 + }; + +#define keylables_map5_0 (char *)" " +#define keylables_map5_1 (char *)" " +#define keylables_map5_2 (char *)" " +#define keylables_map5_3 (char *)" " + +const unsigned short key_map5[] = { + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,0,0 + }; + +const unsigned short matkeys[] = { + 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 + 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 + 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 + 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN + 0x510,0x010,0x110,0x310, // row 4 + }; + +#endif + +#endif diff --git a/MCUME_teensy41/teensymsx/platform_config.h b/MCUME_teensy41/teensymsx/platform_config.h index 4634702..ff73467 100644 --- a/MCUME_teensy41/teensymsx/platform_config.h +++ b/MCUME_teensy41/teensymsx/platform_config.h @@ -4,20 +4,25 @@ #define TEECOMPUTER 1 #ifdef TEECOMPUTER -//#define ILI9341 1 -#define ST7789 1 #define TFTSPI1 1 //#define HAS_T4_VGA 1 -//#define HAS_SND 1 +#define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 -//#define INVX 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 +#define PT8211 1 #else #define HAS_T4_VGA 1 //#define INVX 1 #define INVY 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 +#define PT8211 1 #endif diff --git a/MCUME_teensy41/teensymsx/shared.h b/MCUME_teensy41/teensymsx/shared.h index f8b73ff..aed14a3 100644 --- a/MCUME_teensy41/teensymsx/shared.h +++ b/MCUME_teensy41/teensymsx/shared.h @@ -2,9 +2,6 @@ #ifndef _SHARED_H_ #define _SHARED_H_ - -#define SOUND_PRESENT 1 - #define printf(...) #define LSB_FIRST 1 diff --git a/MCUME_teensy41/teensymsx/t4_dsp.cpp b/MCUME_teensy41/teensymsx/t4_dsp.cpp new file mode 100644 index 0000000..43301fa --- /dev/null +++ b/MCUME_teensy41/teensymsx/t4_dsp.cpp @@ -0,0 +1,1774 @@ +/* + TFT/VGA driver + DMA TFT driver based on C64 ILI9341 dma driver from Frank Bösing, 2017 +*/ + +#include "T4_DSP.h" + +#include +#include + +#include "font8x8.h" + +// TFT constants and variables +#define TFT_LINEARINT 1 +#define LINEARINT_HACK 1 +#define DMA_LINES_PER_BLOCK 64 +#define DMA_NUM_SETTINGS 4 + +#define TFT_SWRESET 0x01 +#define TFT_SLPOUT 0x11 +#define TFT_INVON 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_MADCTL 0x36 +#define TFT_PIXFMT 0x3A +#define TFT_MADCTL_MY 0x80 +#define TFT_MADCTL_MX 0x40 +#define TFT_MADCTL_MV 0x20 +#define TFT_MADCTL_ML 0x10 +#define TFT_MADCTL_RGB 0x00 +#define TFT_MADCTL_BGR 0x08 +#define TFT_MADCTL_MH 0x04 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) +//#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) +//#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) +//#define R16(rgb) ((rgb>>8)&0xf8) +//#define G16(rgb) ((rgb>>3)&0xfc) +//#define B16(rgb) ((rgb<<3)&0xf8) + +// LPSPI4 = SPI0 in Teensy 4.0 +// LPSPI3 = SPI1 in Teensy 4.0 +// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) + +#ifdef TFTSPI1 +#define SPI SPI1 +#define LPSPIP_TDR LPSPI3_TDR +#define LPSPIP_CR LPSPI3_CR +#define LPSPIP_CFGR1 LPSPI3_CFGR1 +#define LPSPIP_TCR LPSPI3_TCR +#define LPSPIP_DER LPSPI3_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX +#else +#define LPSPIP_TDR LPSPI4_TDR +#define LPSPIP_CR LPSPI4_CR +#define LPSPIP_CFGR1 LPSPI4_CFGR1 +#define LPSPIP_TCR LPSPI4_TCR +#define LPSPIP_DER LPSPI4_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX +#endif + +#define SPICLOCK 60000000 +#define SPI_MODE SPI_MODE0 + +// VGA constants and macros +typedef uint8_t vga_pixel; +#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) + +static DMASetting dmasettings[DMA_NUM_SETTINGS]; +static DMAChannel dmatx; +static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K +static volatile uint8_t rstop = 0; +static volatile bool cancelled = false; +static volatile uint8_t curTransfer = 0; +static uint8_t nbTransfer = 0; +static uint16_t * tft_buffer; +static int tft_width; +static int tft_height; +static int tft_stride; + +#define DELAY_MASK 0x80 +PROGMEM static const uint8_t init_commands[] = { + 1+DELAY_MASK, TFT_SWRESET, 150, + 1+DELAY_MASK, TFT_SLPOUT, 255, + 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, + 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, + 1, TFT_INVON, + 1, TFT_DISPON, + 0 +}; + +// VGA constants and variables +// Objective: +// generates VGA signal fully in hardware with as little as possible CPU help + +// Principle: +// QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) +// 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate +// RGB out, combined to create 8bits(/12bits) output. + +// Note: +// - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels +// - experimental resolution: 352x240,352x480 +// - experimental resolution: 512x240,512x480 (not stable) +// - video memory is allocated using malloc in T4 heap +// - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing +// but tried to be compensated by pixel shifting +// - Default is 8bits RRRGGGBB (332) +// But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! +// - Only ok at 600MHz else some disturbances visible + + + +#define TOP_BORDER 40 +#define PIN_HBLANK 15 + +#define PIN_R_B2 33 +#define PIN_R_B1 4 +#define PIN_R_B0 3 +#define PIN_G_B2 2 +#define PIN_G_B1 13 +#define PIN_G_B0 11 +#define PIN_B_B1 12 +#define PIN_B_B0 10 + + +#define DMA_HACK 0x80 + +#define R16(rgb) ((rgb>>8)&0xf8) +#define G16(rgb) ((rgb>>3)&0xfc) +#define B16(rgb) ((rgb<<3)&0xf8) + +// VGA 640x480@60Hz +// Screen refresh rate 60 Hz +// Vertical refresh 31.46875 kHz +// Pixel freq. 25.175 MHz +// +// Visible area 640 25.422045680238 us +// Front porch 16 0.63555114200596 us +// Sync pulse 96 3.8133068520357 us +// Back porch 48 1.9066534260179 us +// Whole line 800 31.777557100298 us + +#define frame_freq 60.0 // Hz +#define line_freq 31.46875 // KHz +#define pix_freq (line_freq*800) // KHz (25.175 MHz) + +// pix_period = 39.7ns +// H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) +#define frontporch_pix 20 //16 +#define backporch_pix 44 //48 + +// Flexio Clock +// PLL3 SW CLOCK (3) => 480 MHz +// PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) +#define FLEXIO_CLK_SEL_PLL3 3 +#define FLEXIO_CLK_SEL_PLL5 2 + +/* Set video PLL */ +// There are /1, /2, /4, /8, /16 post dividers for the Video PLL. +// The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, +// and CCM_ANALOG_MISC2 register sets according to the following equation. +// PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + +// nfact: +// This field controls the PLL loop divider. +// Valid range for DIV_SELECT divider value: 27~54. + +#define POST_DIV_SELECT 2 + +// Full buffer including back/front porch +static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; +static uint32_t dstbuffer __attribute__((aligned(32))); + +// Visible vuffer +static vga_pixel * vga_buffer; +static int vga_width; +static int vga_height; +static int vga_stride; + +static int maxpixperline; +static int left_border; +static int right_border; +static int line_double; +static int pix_shift; +static int ref_div_select; +static int ref_freq_num; +static int ref_freq_denom; +static int ref_pix_shift; +static int combine_shiftreg; + +#ifdef DEBUG +static uint32_t ISRTicks_prev = 0; +volatile uint32_t ISRTicks = 0; +#endif + +uint8_t T4_DSP::_rst; +uint8_t T4_DSP::_cs; +uint8_t T4_DSP::_dc; +uint8_t T4_DSP::_mosi; +uint8_t T4_DSP::_sclk; +uint8_t T4_DSP::_vsync_pin = -1; +DMAChannel T4_DSP::flexio1DMA; +DMAChannel T4_DSP::flexio2DMA; + +static volatile uint32_t VSYNC = 0; +static volatile uint32_t currentLine=0; +#define NOP asm volatile("nop\n\t"); +static gfx_mode_t gfxmode = MODE_UNDEFINED; + + +FASTRUN void T4_DSP::TFT_isr(void) { + dmatx.clearInterrupt(); + curTransfer++; + if (curTransfer >= nbTransfer) { + curTransfer = 0; + if (cancelled) { + dmatx.disable(); + rstop = 1; + } + } + arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); +} + +FASTRUN void T4_DSP::QT3_isr(void) { + TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); + TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); + + cli(); + + // V-PULSE + if (currentLine > 0) { + digitalWrite(_vsync_pin, 1); + VSYNC = 0; + } else { + digitalWrite(_vsync_pin, 0); + VSYNC = 1; + } + + currentLine++; + currentLine = currentLine % 525; + + + uint32_t y = (currentLine - TOP_BORDER) >> line_double; + // Visible area + + if (y >= 0 && y < vga_height) { + // Disable DMAs + //DMA_CERQ = flexio2DMA.channel; + //DMA_CERQ = flexio1DMA.channel; + + // Setup source adress + // Aligned 32 bits copy + unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; + flexio2DMA.TCD->SADDR = p; + if (pix_shift & DMA_HACK) + { + // Unaligned copy + uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; + flexio1DMA.TCD->SADDR = p2; + } + else { + p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 + flexio1DMA.TCD->SADDR = p; + } + + // Enable DMAs + //flexio2DMA.enable(); + //flexio1DMA.enable(); + DMA_SERQ = flexio2DMA.channel; + DMA_SERQ = flexio1DMA.channel; + arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); + } + sei(); + +#ifdef DEBUG + ISRTicks++; +#endif + asm volatile("dsb"); +} + +static void setDmaStruct() { + uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; + uint16_t * fb = (uint16_t*)malloc(remaining); + tft_buffer = fb; + tft_width = TFT_WIDTH; + tft_height = TFT_HEIGHT; + tft_stride = TFT_WIDTH; + uint16_t col=RGBVAL16(0x00,0x00,0x00); + int i=0; + while (remaining > 0) { + int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); + blocks[i] = fb; + for (int j=0;jATTR_DST = 1; + dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); + dmasettings[i].interruptAtCompletion(); + fb += len/2; + remaining -= len; + i++; + } + dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); + nbTransfer = i; +} + +static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 +{ +//if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; + CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE + | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 + | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); + CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; + CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock + const int div_post_pll = 1; // other values: 2,4 + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass +} + +T4_DSP::T4_DSP() +{ + _cs = TFT_CS; + _dc = TFT_DC; + _rst = TFT_RST; + _mosi = TFT_MOSI; + _sclk = TFT_SCLK; + pinMode(_dc, OUTPUT); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, 1); + digitalWrite(_dc, 1); + _vsync_pin = 8; +} + + +void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { + int dx=0; + int dy=0; + digitalWrite(_dc, 0); + SPI.transfer(TFT_CASET); + digitalWrite(_dc, 1); + SPI.transfer16(x1+dx); + digitalWrite(_dc, 1); + SPI.transfer16(x2+dx); + digitalWrite(_dc, 0); + SPI.transfer(TFT_PASET); + digitalWrite(_dc, 1); + SPI.transfer16(y1+dy); + digitalWrite(_dc, 1); + SPI.transfer16(y2+dy); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + return; +} + +void T4_DSP::tft_setup(bool isST) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + // RESET if reset pin defined + if (_rst != 0xff) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + const uint8_t *addr = init_commands; + uint8_t count; + digitalWrite(_cs, 0); + while (count = *addr++) { + uint8_t command = *addr++; + if ( (command == TFT_INVON) && (!isST) ) { + // Skip TFT_INVON for ILI + } + else { + digitalWrite(_dc, 0); // command + SPI.transfer(command); + uint16_t ms = count & DELAY_MASK; + count &= ~DELAY_MASK; + while (--count > 0) { // data + uint8_t data = *addr++; + if ( (command == TFT_MADCTL) && (isST) ) { + data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; + } + digitalWrite(_dc, 1); + SPI.transfer(data); + } + if (ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + digitalWrite(_cs, 1); + SPI.endTransaction(); + delay(2); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + } + } + } + digitalWrite(_cs, 1); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + SPI.endTransaction(); + /* + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_dc, 0); + digitalWrite(_cs, 0); + SPI.transfer(TFT_MADCTL); + digitalWrite(_dc, 1); + SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); + // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); + digitalWrite(_cs, 1); + SPI.endTransaction(); + */ + cancelled = false; +} + +// display VGA image +gfx_error_t T4_DSP::begin(gfx_mode_t mode) +{ + uint32_t flexio_clock_div; + combine_shiftreg = 0; +// int div_select = 49; +// int num = 135; +// int denom = 100; + int div_select = 20; + int num = 9800; + int denom = 10000; + int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; + int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; + set_videoClock(div_select,num,denom,true); + +#ifdef DEBUG + Serial.println(mode); + Serial.println("mode"); +#endif + + switch(mode) + { + case MODE_TFTILI_320x240: +#ifdef DEBUG + Serial.println("TFTILI_320x240"); +#endif + tft_setup(false); + gfxmode = mode; + break; + case MODE_TFTST_320x240: +#ifdef DEBUG + Serial.println("TFTST_320x240"); +#endif + tft_setup(true); + gfxmode = mode; + break; + + case MODE_VGA_320x240: +#ifdef DEBUG + Serial.println("VGA_320x240"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_320x480: +#ifdef DEBUG + Serial.println("VGA_320x480"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_640x240: +#ifdef DEBUG + Serial.println("VGA_640x240"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/pix_freq; + line_double = 1; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_640x480: +#ifdef DEBUG + Serial.println("VGA_640x480"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = (flexio_freq/pix_freq); + line_double = 0; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_512x240: +#ifdef DEBUG + Serial.println("VGA_512x240"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 1; + pix_shift = 0; + break; + + case MODE_VGA_512x480: +#ifdef DEBUG + Serial.println("VGA_512x480"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 0; + pix_shift = 0; + break; + + case MODE_VGA_352x240: +#ifdef DEBUG + Serial.println("VGA_352x240"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_352x480: +#ifdef DEBUG + Serial.println("VGA_352x480"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + } + + if (mode >= MODE_VGA_320x240) + { + if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { + fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); + digitalWrite(_cs, 0); + digitalWrite(_dc, 0); + SPI.transfer(TFT_DISPOFF); + digitalWrite(_cs, 1); + delay(20); + digitalWrite(_cs, 0); + digitalWrite(_cs, 1); + } + gfxmode = mode; + + maxpixperline = vga_stride; + // Save param for tweek adjustment + ref_div_select = div_select; + ref_freq_num = num; + ref_freq_denom = denom; + ref_pix_shift = pix_shift; + +#ifdef DEBUG + Serial.println("frequency"); + Serial.println(flexio_freq); + Serial.println("div"); + Serial.println(flexio_freq/pix_freq); +#endif + + pinMode(_vsync_pin, OUTPUT); + pinMode(PIN_HBLANK, OUTPUT); + + /* Basic pin setup FlexIO1 */ + pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 + pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 + pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 + pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 + /* Basic pin setup FlexIO2 */ + pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 + pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 + pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 + pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 + + /* High speed and drive strength configuration */ + *(portControlRegister(PIN_G_B2)) = 0xFF; + *(portControlRegister(PIN_R_B0)) = 0xFF; + *(portControlRegister(PIN_R_B1)) = 0xFF; + *(portControlRegister(PIN_R_B2)) = 0xFF; + *(portControlRegister(PIN_B_B0)) = 0xFF; + *(portControlRegister(PIN_B_B1)) = 0xFF; + *(portControlRegister(PIN_G_B0)) = 0xFF; + *(portControlRegister(PIN_G_B1)) = 0xFF; + + /* Set clock for FlexIO1 and FlexIO2 */ + CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) + | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); + CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) + | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); + + + /* Set up pin mux FlexIO1 */ + *(portConfigRegister(PIN_G_B2)) = 0x14; + *(portConfigRegister(PIN_R_B0)) = 0x14; + *(portConfigRegister(PIN_R_B1)) = 0x14; + *(portConfigRegister(PIN_R_B2)) = 0x14; + /* Set up pin mux FlexIO2 */ + *(portConfigRegister(PIN_B_B0)) = 0x14; + *(portConfigRegister(PIN_B_B1)) = 0x14; + *(portConfigRegister(PIN_G_B0)) = 0x14; + *(portConfigRegister(PIN_G_B1)) = 0x14; + + /* Enable the clock */ + CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + /* Enable the FlexIO with fast access */ + FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + + uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; + uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; + + /* Shifter 0 registers for FlexIO2 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 + inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter + stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled + startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable + timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 + timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock + pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output + pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity + shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode + /* Shifter 0 registers for FlexIO1 */ + FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + /* Shifter 0 registers for FlexIO1 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 + FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + if (combine_shiftreg) { + pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled + FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + } + /* Timer 0 registers for FlexIO2 */ + timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset + timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output + timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset + timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare + timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert + stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled + startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled + if (combine_shiftreg) { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag + } + else { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag + } + triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low + triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected + pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled + //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 + //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high + timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode + // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) + + int shifts_per_transfer; + if (combine_shiftreg) { + shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 + } + else { + shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 + } + FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); + /* Timer 0 registers for FlexIO1 */ + FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); +#ifdef DEBUG + Serial.println("FlexIO setup complete"); +#endif + + /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ + if (combine_shiftreg) { + FLEXIO2_SHIFTSDEN |= (1<<1); + FLEXIO1_SHIFTSDEN |= (1<<1); + } + else { + FLEXIO2_SHIFTSDEN |= (1<<0); + FLEXIO1_SHIFTSDEN |= (1<<0); + } + /* Disable DMA channel so it doesn't start transferring yet */ + flexio1DMA.disable(); + flexio2DMA.disable(); + /* Set up DMA channel to use Shifter 0 trigger */ + flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); + flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); + + + if (combine_shiftreg) { + flexio2DMA.TCD->NBYTES = 8; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 8; + flexio2DMA.TCD->CITER = maxpixperline / 8; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + flexio1DMA.TCD->NBYTES = 8; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 8; + flexio1DMA.TCD->CITER = maxpixperline / 8; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Setup DMA2 Flexio2 copy + flexio2DMA.TCD->NBYTES = 4; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 4; + flexio2DMA.TCD->CITER = maxpixperline / 4; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + // Setup DMA1 Flexio1 copy + // Use pixel shift to avoid color smearing? + if (pix_shift & DMA_HACK) + { + if (pix_shift & 0x3 == 0) { + // Aligned 32 bits copy (32bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Unaligned (source) 32 bits copy (8bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 1; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion + } + } + else + { + // Aligned 32 bits copy + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + } + +#ifdef DEBUG + Serial.println("DMA setup complete"); +#endif + + // enable clocks for QTIMER3: generates the 15KHz for hsync + // Pulse: + // low : 3.8133 us => 569x6.7ns + // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) + // (OLD TEST) + // (4us low, 28us high => 32us) + // (597x6.7ns for 4us) + // (4179x6.7ns for 28us) + CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 + //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 + + #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz + #define MARGIN_D 1000 + + TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer + // Invert output pin as we want the interupt on rising edge + TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) + TMR3_CNTR3 = 0; + TMR3_LOAD3 = 0; + + /* Inverted timings */ + unsigned long long cpu_freq = F_CPU; + unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; + int rate2 = rate; + + int substract = 1; + if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { + substract=5; + rate2=1652; + } + + #ifdef DEBUG + Serial.print("MARGIN_N is: "); + Serial.println(rate2, DEC); + Serial.print("SUBSTRACT is: "); + Serial.println(substract, DEC); +#endif + TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; + TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; + /* + TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; + */ + TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on + TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), + // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) + //configure Teensy pin Compare output + IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 + attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function + NVIC_ENABLE_IRQ(IRQ_QTIMER3); +#ifdef DEBUG + Serial.println("QTIMER3 setup complete"); + Serial.print("V-PIN is "); + Serial.println(_vsync_pin); +#endif + + /* initialize gfx buffer */ + if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift + if (gfxbuffer == NULL) return(GFX_ERROR); +#ifdef DEBUG + Serial.println("Memory allocated"); +#endif + + memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); + vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; +#ifdef DEBUG + Serial.println(vga_stride); + Serial.println(vga_height); + Serial.println("Screen cleared"); +#endif + } + + return(GFX_OK); +} + +gfx_mode_t T4_DSP::getMode(void) +{ + return gfxmode; +} + +void T4_DSP::startRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + curTransfer = 0; + rstop = 0; + //dmatx.begin(true); + dmatx.attachInterrupt(TFT_isr); + setDmaStruct(); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + + digitalWrite(_cs, HIGH); + SPI.begin(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + + LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: + LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX + LPSPIP_TCR = 15; // Framesize 16 Bits + //LPSPIP_FCR = 0; // Fifo Watermark + LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable + LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: + dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); + + dmatx = dmasettings[0]; + digitalWrite(_cs, 0); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + dmatx.enable(); + } +} + + +void T4_DSP::stopRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + rstop = 1; + unsigned long m = millis(); + cancelled = true; + while (!rstop) { + if ((millis() - m) > 100) break; + delay(10); + asm volatile("wfi"); + }; + rstop = 0; + delay(50); + cancelled = false; + dmatx.detachInterrupt(); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + SPI.end(); +#ifdef ST7789 +// begin(gfxmode); +#endif + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + } +} + +int T4_DSP::get_frame_buffer_size(int *width, int *height) { + if (gfxmode < MODE_VGA_320x240) { + if (width != nullptr) *width = tft_width; + if (height != nullptr) *height = tft_height; + return tft_stride; + } + else { + if (width != nullptr) *width = vga_width; + if (height != nullptr) *height = vga_height; + return vga_stride; + } +} + +void T4_DSP::waitSync() +{ + if (gfxmode >= MODE_VGA_320x240) { + while (VSYNC == 0) {}; + } +} + +void T4_DSP::waitLine(int line) +{ + if (gfxmode >= MODE_VGA_320x240) { + while (currentLine != line) {}; + } +} + +/*********************************************************************************************** + No DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreenNoDma(uint16_t color) { + if (gfxmode < MODE_VGA_320x240) { + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + int i,j; + for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(arx, ary, arx+arw-1, ary+arh-1); + bitmap = bitmap + bmp_offy*w + bmp_offx; + for (int row=0;row> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + bits = *charpt++; + //digitalWrite(_dc, 1); + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + x +=8; + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + else { + drawText(x, y, text, fgcolor, bgcolor, doublesize); + } +} + + +/*********************************************************************************************** + DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreen(uint16_t color) { + int i,j; + if (gfxmode < MODE_VGA_320x240) { + for (j=0; j> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + dst=&tft_buffer[l*tft_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + x +=8; + } + } + else { + vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); + vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); + vga_pixel * dst; + while ((c = *text++)) { + const unsigned char * charpt=&font8x8[c][0]; + int l=y; + for (int i=0;i<8;i++) + { + unsigned char bits; + if (doublesize) { + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + x +=8; + } + } +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { + drawSprite(x,y,bitmap, 0,0,0,0); +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) +{ + int bmp_offx = 0; + int bmp_offy = 0; + uint16_t *bmp_ptr; + int w =*bitmap++; + int h = *bitmap++; + if ( (arw == 0) || (arh == 0) ) { + // no crop window + arx = x; + ary = y; + arw = w; + arh = h; + } + else { + if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + int l=ary; + bitmap = bitmap + bmp_offy*w + bmp_offx; + + if (gfxmode < MODE_VGA_320x240) { + for (int row=0;row tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]; + pos +=step; + } + #endif + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i 2) ) y += (tft_height-height)/2; + uint16_t * dst=&tft_buffer[y*tft_stride]; + if (width > tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]]; + pos +=step; + } +#endif + } + else if ((width*2) == tft_width) { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]]; + *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i tft_width) { + int step = ((width << 8)/tft_width); + int pos = 0; + for (int i=0; i> 8]]; + pos +=step; + } + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = pix; + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i +#include +#endif + +#include "platform_config.h" +#include "iopins.h" + + + +#ifndef TFT_WIDTH +#define TFT_WIDTH 320 +#endif +#define TFT_REALWIDTH 320 + +#ifndef TFT_HEIGHT +#define TFT_HEIGHT 240 +#endif +#define TFT_REALHEIGHT 240 + + +typedef enum gfx_mode_t +{ + MODE_UNDEFINED = 0, + MODE_TFTILI_320x240 = 1, + MODE_TFTST_320x240 = 2, + MODE_VGA_320x240 = 3, + MODE_VGA_320x480 = 4, + MODE_VGA_352x240 = 5, + MODE_VGA_352x480 = 6, + MODE_VGA_512x240 = 7, + MODE_VGA_512x480 = 8, + MODE_VGA_640x240 = 9, + MODE_VGA_640x480 = 10 +} gfx_mode_t; + +typedef enum gfx_error_t +{ + GFX_OK = 0, + GFX_ERROR = -1 +} gfx_error_t; + + +#ifdef __cplusplus + +class T4_DSP +{ + public: + T4_DSP(); + + gfx_error_t begin(gfx_mode_t mode); + gfx_mode_t getMode(void); + void startRefresh(void); + void stopRefresh(); + + int get_frame_buffer_size(int *width, int *height); + void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); + + // wait next Vsync + void waitSync(); + void waitLine(int line); + + // NoDMA functions + void fillScreenNoDma(uint16_t color); + void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + // DMA functions + void fillScreen(uint16_t color); + void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + void writeLine(int width, int height, int y, uint16_t *buf); + void writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + void writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16); + void writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + + protected: + static uint8_t _rst, _cs, _dc; + static uint8_t _mosi, _sclk; + static uint8_t _vsync_pin; + static DMAChannel flexio1DMA; + static DMAChannel flexio2DMA; + void tft_setup(bool isST); + static void TFT_isr(void); + static void QT3_isr(void); +}; + +#endif +#endif diff --git a/MCUME_teensy41/teensymsx/teensymsx.ino b/MCUME_teensy41/teensymsx/teensymsx.ino index 211fe17..88a5551 100644 --- a/MCUME_teensy41/teensymsx/teensymsx.ino +++ b/MCUME_teensy41/teensymsx/teensymsx.ino @@ -3,132 +3,20 @@ extern "C" { #include "emuapi.h" } -#include "fmsx.h" - -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -TFT_T_DMA tft; -#else -#include "tft_t_dma.h" -TFT_T_DMA tft = TFT_T_DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, TFT_TOUCH_CS, TFT_TOUCH_INT); -#endif - -bool vgaMode = false; - -static unsigned char palette8[PALETTE_SIZE]; -static unsigned short palette16[PALETTE_SIZE]; -static IntervalTimer myTimer; -volatile boolean vbl=true; -static int skip=0; -static elapsedMicros tius; - -static void vblCount() { - if (vbl) { - vbl = false; - } else { - vbl = true; - } -} - -void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) -{ - if (index>8, - 320 & 0xFF, // YEND = 320 - ST7735_INVON , DELAY, // 7: hack - 10, - ST7735_NORON , DELAY, // 8: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 9: Main screen turn on, no args, w/delay - 255 -#endif -}; - -static void dmaInterrupt() { - dmatx.clearInterrupt(); - curTransfer++; - if (curTransfer >= nbTransfer) { - curTransfer = 0; - if (cancelled) { - dmatx.disable(); - rstop = 1; - } - } - arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2); -} - -static void setDmaStruct() { - uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; - int i=0; - uint16_t col=RGBVAL16(0x00,0x00,0x00);; - while (remaining > 0) { - uint16_t * fb = blocks[i]; - int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining); -#ifdef TFT_DEBUG - Serial.println((unsigned long)blocks[i]); - Serial.println(remaining); -#endif - switch (i) { - case 0: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb0[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0x00); -#endif - break; - case 1: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb1[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0xff); -#endif - break; - case 2: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb2[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0x00,0xff); -#endif - break; - case 3: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb3[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0xff,0x00,0xff); -#endif - break; - } - blocks[i] = fb; - if (blocks[i] == 0) { - Serial.print("ILI9341 allocaltion failed for block "); - Serial.println(i); - delay(10000); - } - - for (int j=0;jATTR_DST = 1; - dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); - dmasettings[i].interruptAtCompletion(); - remaining -= len; - i++; - } - dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); - nbTransfer = i; -#ifdef TFT_DEBUG - Serial.println(nbTransfer); -#endif -} - - -TFT_T_DMA::TFT_T_DMA(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso, uint8_t touch_cs, uint8_t touch_irq) -{ - _cs = cs; - _dc = dc; - _rst = rst; - _mosi = mosi; - _sclk = sclk; - _miso = miso; - pinMode(_dc, OUTPUT); - pinMode(_cs, OUTPUT); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); - if ( (touch_cs != 255) && (touch_irq != 255) ) { - _touch_irq = touch_irq; - _touch_cs = touch_cs; - pinMode(_touch_cs, OUTPUT); - pinMode(touch_irq, INPUT_PULLUP); - digitalWrite(_touch_cs, 1); - } -} - - -void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { - int dx=0; - int dy=0; -#ifdef ST7789 - if (TFT_REALWIDTH == TFT_REALHEIGHT) - { -#ifdef ROTATE_SCREEN - if (!flipped) { - dy += 80; - } -#else - if (flipped) { - dx += 80; - } -#endif - } -#endif - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - SPI.transfer16(x1+dx); - digitalWrite(_dc, 1); - SPI.transfer16(x2+dx); - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - digitalWrite(_dc, 1); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - return; - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - - SPI.transfer16(x1+dx); - SPI.transfer16(x2+dx); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - -void TFT_T_DMA::begin(void) { - SPI.setMOSI(_mosi); - SPI.setMISO(_miso); - SPI.setSCK(_sclk); - SPI.begin(); - - // Initialize display - if (_rst != 0xff) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - const uint8_t *addr = init_commands; - digitalWrite(_cs, 0); -#ifdef ILI9341 - while (1) { - uint8_t count = *addr++; - if (count-- == 0) break; - - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - - while (count-- > 0) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - } - - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(ILI9341_DISPON); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); -#endif -#ifdef ST7789 - uint8_t numCommands, numArgs; - uint16_t ms; - numCommands = *addr++; // Number of commands to follow - while(numCommands--) { // For each command... - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - numArgs = *addr++; // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs > 1) { // For each argument... - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - numArgs--; - } - - if (numArgs) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - if(ms) { - ms = *addr++; // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - digitalWrite(_cs, 1); - SPI.endTransaction(); - delay(ms); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - } - } - digitalWrite(_cs, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - SPI.endTransaction(); - - cancelled = false; - -#ifdef FLIP_SCREEN - flipscreen(true); -#else - flipscreen(false); -#endif -#ifdef ST7789 - if (TFT_REALWIDTH != TFT_REALHEIGHT) - { - flipscreen(true); - } -#endif -}; - - - -void TFT_T_DMA::flipscreen(bool flip) -{ - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(TFT_MADCTL); - digitalWrite(_dc, 1); - if (flip) { - flipped=true; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB); -#endif -#endif - } - else { - flipped=false; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB); -#endif -#endif - } - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - -boolean TFT_T_DMA::isflipped(void) -{ - return(flipped); -} - - -#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) - - -void TFT_T_DMA::startDMA(void) { - curTransfer = 0; - rstop = 0; - //dmatx.begin(true); - dmatx.attachInterrupt(dmaInterrupt); - setDmaStruct(); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - - digitalWrite(_cs, HIGH); - SPI.begin(); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); - - - LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: - LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX - LPSPIP_TCR = 15; // Framesize 16 Bits - //LPSPIP_FCR = 0; // Fifo Watermark - LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable - LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: - dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); - - dmatx = dmasettings[0]; - digitalWrite(_cs, 0); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - dmatx.enable(); -} - - -void TFT_T_DMA::stopDMA(void) { - rstop = 0; - wait(); - delay(50); - cancelled = false; - dmatx.detachInterrupt(); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - SPI.end(); -#ifdef ST7789 - begin(); -#endif -#ifdef ILI9341 - SPI.begin(); - digitalWrite(_cs, 0); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - SPI.endTransaction(); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); -} - -void TFT_T_DMA::wait(void) { - rstop = 1; - unsigned long m = millis(); - cancelled = true; - while (!rstop) { - if ((millis() - m) > 100) break; - delay(10); - asm volatile("wfi"); - }; - rstop = 0; -} - -int TFT_T_DMA::get_frame_buffer_size(int *width, int *height){ - if (width != nullptr) *width = TFT_REALWIDTH; - if (height != nullptr) *height = TFT_REALHEIGHT; - return TFT_REALWIDTH; -} - - -/*********************************************************************************************** - Touch functions - ***********************************************************************************************/ -/* Code based on ... - * - * @file XPT2046.cpp - * @date 19.02.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the XPT2046 driver for Arduino. - */ - -#define ADC_MAX 0x0fff - -void TFT_T_DMA::enableTouchIrq() -{ - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 }; - SPI.transfer((void*)&buf[0],3); - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); -} - -//Default callibration for non flipped -#define TX_MIN 30 -#define TY_MIN 20 -#define TX_MAX 300 -#define TY_MAX 220 - -//Default callibration for flipped -#define TFX_MIN 20 -#define TFY_MIN 25 -#define TFX_MAX 288 -#define TFY_MAX 221 - -static uint16_t txMin; -static uint16_t tyMin; -static uint16_t txMax; -static uint16_t tyMax; - - -void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { - if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) { - txMin = xMin; - tyMin = yMin; - txMax = xMax; - tyMax = yMax; - } - else { - if (flipped) { - txMin = TFX_MIN; - tyMin = TFY_MIN; - txMax = TFX_MAX; - tyMax = TFY_MAX; - } - else { - txMin = TX_MIN; - tyMin = TY_MIN; - txMax = TX_MAX; - tyMax = TY_MAX; - } - } -} - - -void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - if ( TOUCH_ENABLED() ) { - uint16_t x = 0; - uint16_t y = 0; - uint16_t z1 = 0; - uint16_t z2 = 0; - uint8_t i = 0; - int16_t xraw=0, yraw=0; - - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - - for(; i < 15; i++) { - // SPI requirer 32bit aliment - uint8_t buf[12] = { - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00 - }; - SPI.transfer(&buf[0], &buf[0], 12); - y += (buf[1] << 8 | buf[2])>>3; - x += (buf[4] << 8 | buf[5])>>3; - z1 += (buf[7] << 8 | buf[8])>>3; - z2 += (buf[10] << 8 | buf[11])>>3; - } - enableTouchIrq(); - - if(i == 0) { - *oX = 0; - *oY = 0; - *oZ = 0; - } - else { - x /= i; - y /= i; - z1 /= i; - z2 /= i; - } - - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); - int z = z1 + ADC_MAX - z2; - if (flipped) { - xraw = x; - yraw = y; - } else { - xraw = ADC_MAX - x; - yraw = ADC_MAX - y; - } - xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1); - yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1); - - *oX = xraw; - *oY = yraw; - *oZ = z; - } - else - { - *oX = 0; - *oY = 0; - *oZ = 0; - } -} - -void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - readRaw(oX,oY,oZ); - // callibrate ... - if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin); - if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin); - //Serial.print(*oX); - //Serial.print(" "); - //Serial.println(*oY); -} - - -/*********************************************************************************************** - No DMA functions - ***********************************************************************************************/ -void TFT_T_DMA::fillScreenNoDma(uint16_t color) { - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - int i,j; - for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(arx, ary, arx+arw-1, ary+arh-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - bits = *charpt++; - //digitalWrite(_dc, 1); - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - x +=8; -#ifdef ILI9341 - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); -#endif - digitalWrite(_cs, 1); - SPI.endTransaction(); - } - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - - - -/*********************************************************************************************** - DMA functions - ***********************************************************************************************/ -uint16_t * TFT_T_DMA::getLineBuffer(int j) -{ - uint16_t * block=blocks[j>>6]; - return(&block[(j&0x3F)*TFT_REALWIDTH]); -} - -void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) { - uint8_t *buffer=buf; - uint8_t *src; - - int i,j,y=0; - if (width*2 <= TFT_REALWIDTH) { - for (j=0; j>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH]; - for (i=0; i>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x]; - for (i=0; i>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - block=blocks[l>>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt++; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - x +=8; - } -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { - drawSprite(x,y,bitmap, 0,0,0,0); -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) -{ - int bmp_offx = 0; - int bmp_offy = 0; - uint16_t *bmp_ptr; - - int w =*bitmap++; - int h = *bitmap++; - - - if ( (arw == 0) || (arh == 0) ) { - // no crop window - arx = x; - ary = y; - arw = w; - arh = h; - } - else { - if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - int l=ary; - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx]; - bmp_ptr = (uint16_t*)bitmap; - for (int col=0;col -#include -#include -#endif - -#include "tft_t_dma_config.h" - -#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) -#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define R16(rgb) ((rgb>>8)&0xf8) -#define G16(rgb) ((rgb>>3)&0xfc) -#define B16(rgb) ((rgb<<3)&0xf8) - -#define PAL_COLOR_MASK 0xff - -#ifdef LOHRES -#define TFT_WIDTH 240 -#define TFT_REALWIDTH 240 -#else -#define TFT_WIDTH 272 -#define TFT_REALWIDTH 320 -#endif -#define TFT_HEIGHT 228 -#define TFT_REALHEIGHT 240 - -//#define WIDTH 272 -//#define HEIGHT 228 - -#define LINES_PER_BLOCK 64 -#define NR_OF_BLOCK 4 -#define SCREEN_DMA_NUM_SETTINGS NR_OF_BLOCK - - -#ifdef ILI9341 - -#define ILI9341_NOP 0x00 -#define ILI9341_SWRESET 0x01 -#define ILI9341_RDDID 0x04 -#define ILI9341_RDDST 0x09 - -#define ILI9341_SLPIN 0x10 -#define ILI9341_SLPOUT 0x11 -#define ILI9341_PTLON 0x12 -#define ILI9341_NORON 0x13 - -#define ILI9341_RDMODE 0x0A -#define ILI9341_RDMADCTL 0x0B -#define ILI9341_RDPIXFMT 0x0C -#define ILI9341_RDIMGFMT 0x0D -#define ILI9341_RDSELFDIAG 0x0F - -#define ILI9341_INVOFF 0x20 -#define ILI9341_INVON 0x21 -#define ILI9341_GAMMASET 0x26 -#define ILI9341_DISPOFF 0x28 -#define ILI9341_DISPON 0x29 - -#define ILI9341_CASET 0x2A -#define ILI9341_PASET 0x2B -#define ILI9341_RAMWR 0x2C -#define ILI9341_RAMRD 0x2E - -#define ILI9341_PTLAR 0x30 -#define ILI9341_MADCTL 0x36 -#define ILI9341_VSCRSADD 0x37 -#define ILI9341_PIXFMT 0x3A - -#define ILI9341_FRMCTR1 0xB1 -#define ILI9341_FRMCTR2 0xB2 -#define ILI9341_FRMCTR3 0xB3 -#define ILI9341_INVCTR 0xB4 -#define ILI9341_DFUNCTR 0xB6 - -#define ILI9341_PWCTR1 0xC0 -#define ILI9341_PWCTR2 0xC1 -#define ILI9341_PWCTR3 0xC2 -#define ILI9341_PWCTR4 0xC3 -#define ILI9341_PWCTR5 0xC4 -#define ILI9341_VMCTR1 0xC5 -#define ILI9341_VMCTR2 0xC7 - -#define ILI9341_RDID1 0xDA -#define ILI9341_RDID2 0xDB -#define ILI9341_RDID3 0xDC -#define ILI9341_RDID4 0xDD - -#define ILI9341_GMCTRP1 0xE0 -#define ILI9341_GMCTRN1 0xE1 - -#define ILI9341_MADCTL_MY 0x80 -#define ILI9341_MADCTL_MX 0x40 -#define ILI9341_MADCTL_MV 0x20 -#define ILI9341_MADCTL_ML 0x10 -#define ILI9341_MADCTL_RGB 0x00 -#define ILI9341_MADCTL_BGR 0x08 -#define ILI9341_MADCTL_MH 0x04 - -#define TFT_CASET ILI9341_CASET -#define TFT_PASET ILI9341_PASET -#define TFT_RAMWR ILI9341_RAMWR -#define TFT_MADCTL ILI9341_MADCTL - -#endif - - -#ifdef ST7789 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_RGB 0x00 -#define ST77XX_MADCTL_BGR 0x08 -#define ST77XX_MADCTL_MH 0x04 - -#define TFT_CASET ST7735_CASET -#define TFT_PASET ST7735_RASET -#define TFT_RAMWR ST7735_RAMWR -#define TFT_MADCTL ST7735_MADCTL - -#endif - - - -#ifdef __cplusplus - -class TFT_T_DMA -{ - public: - TFT_T_DMA(uint8_t _CS, uint8_t _DC, uint8_t _RST = 255, uint8_t _MOSI=11, uint8_t _SCLK=13, uint8_t _MISO=12, uint8_t touch_cs=38, uint8_t touch_irq=37); - - void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); - void begin(void); - void flipscreen(bool flip); - boolean isflipped(void); - void startDMA(void); - void stopDMA(); - int get_frame_buffer_size(int *width, int *height); - - // Touch screen functions - #define TOUCH_ENABLED() ((_touch_cs != 255) && (_touch_irq != 255)) - bool isTouching(void) { return ((!TOUCH_ENABLED())?false:(digitalRead(_touch_irq) == LOW)); } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax); - - // NoDMA functions - void writeScreenNoDma(const uint16_t *pcolors); - void fillScreenNoDma(uint16_t color); - void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - // DMA functions - uint16_t * getLineBuffer(int j); - void writeScreen(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int y, uint16_t *buf); - void fillScreen(uint16_t color); - void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - protected: - uint8_t _rst, _cs, _dc; - uint8_t _miso, _mosi, _sclk; - uint8_t _touch_irq=255, _touch_cs=255; - bool flipped=false; - - void wait(void); - void enableTouchIrq(); -}; - -#endif -#endif - - diff --git a/MCUME_teensy41/teensymsx/tft_t_dma_config.h b/MCUME_teensy41/teensymsx/tft_t_dma_config.h deleted file mode 100644 index d8200a2..0000000 --- a/MCUME_teensy41/teensymsx/tft_t_dma_config.h +++ /dev/null @@ -1,13 +0,0 @@ -#include "platform_config.h" - -//#define ST7789 1 -//#define ILI9341 1 - -#define TFT_LINEARINT 1 -#define LINEARINT_HACK 1 - -//#define FLIP_SCREEN 1 -//#define TFT_DEBUG 1 -#if defined(__IMXRT1052__) || defined(__IMXRT1062__) -#define TFT_STATICFB 1 -#endif diff --git a/MCUME_teensy41/teensymsx/vga_t_dma.h b/MCUME_teensy41/teensymsx/vga_t_dma.h deleted file mode 100644 index 81a986b..0000000 --- a/MCUME_teensy41/teensymsx/vga_t_dma.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - Wrapping class to extend VGA_T4 to TFT_T_DMA -*/ - -#ifndef _VGA_T_DMAH_ -#define _VGA_T_DMAH_ - -#ifdef __cplusplus -#include -#endif - - -#define RGBVAL16(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) - - - - -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 - -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - - - -#ifdef __cplusplus - -class TFT_T_DMA: public VGA_T4 -{ - public: - // Fake touch screen functions - bool isTouching(void) { return false; } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { } - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { }; - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { } - - // fake DMA functions - void startDMA(void) { }; - void stopDMA(void) { }; - - // fake no DMA functions - void writeScreenNoDma(const vga_pixel *pcolors) { writeScreen(pcolors); } - void fillScreenNoDma(vga_pixel color) { clear(color); } - void drawTextNoDma(int16_t x, int16_t y, const char * text, vga_pixel fgcolor, vga_pixel bgcolor, bool doublesize) { drawText(x,y,text,fgcolor,bgcolor,doublesize); } - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, vga_pixel color) { drawRect(x, y, w, h, color); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap) { drawSprite(x, y, bitmap); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh) { drawSprite(x, y, bitmap, croparx, cropary, croparw, croparh); } -}; - - -#endif -#endif diff --git a/MCUME_teensy41/teensymsx/fmsx.cpp b/MCUME_teensy41/teensymsx/wrapemu.cpp similarity index 97% rename from MCUME_teensy41/teensymsx/fmsx.cpp rename to MCUME_teensy41/teensymsx/wrapemu.cpp index 6c35dca..8ced9b5 100644 --- a/MCUME_teensy41/teensymsx/fmsx.cpp +++ b/MCUME_teensy41/teensymsx/wrapemu.cpp @@ -1,7 +1,5 @@ #include #include "emuapi.h" -#include "tft_t_dma.h" -#include "iopins.h" extern "C" { #include "shared.h" @@ -60,7 +58,7 @@ byte *LoadROM(const char *Name,int Size,byte *Buf); int LoadCart(const char *Name,int Slot); int GuessROM(const byte *Buf,int Size); void SetMegaROM(int Slot,byte P0,byte P1,byte P2,byte P3); -void MapROM(word A,byte V); /* Switch MegaROM banks */ +void MapROM(WORD A,byte V); /* Switch MegaROM banks */ extern "C" { void SSlot(byte V); /* Switch secondary slots */ } @@ -70,8 +68,8 @@ void PPIOut(byte New,byte Old); /* Set PPI bits (key click, etc.) */ void CheckSprites(void); /* Check collisions and 5th sprite */ byte RTCIn(byte R); /* Read RTC registers */ byte SetScreen(void); /* Change screen mode */ -word SetIRQ(byte IRQ); /* Set/Reset IRQ */ -word StateID(void); /* Compute emulation state ID */ +WORD SetIRQ(byte IRQ); /* Set/Reset IRQ */ +WORD StateID(void); /* Compute emulation state ID */ static void RefreshLineF(register byte Y); static void RefreshLine0(register byte Y); @@ -206,7 +204,7 @@ byte *ChrGen,*ChrTab,*ColTab; /* VDP tables (screen) */ byte *SprGen,*SprTab; /* VDP tables (sprites) */ int ChrGenM,ChrTabM,ColTabM; /* VDP masks (screen) */ int SprTabM; /* VDP masks (sprites) */ -word VAddr; /* VRAM address in VDP */ +WORD VAddr; /* VRAM address in VDP */ byte VKey,PKey,WKey; /* Status keys for VDP */ byte FGColor,BGColor; /* Colors */ byte XFGColor,XBGColor; /* Second set of colors */ @@ -220,10 +218,10 @@ byte ALatch; /* Address buffer */ int Palette[16]; /* Current palette */ /** Places in DiskROM to be patched with ED FE C9 ************/ -const word DiskPatches[] = { 0x4010,0x4013,0x4016,0x401C,0x401F,0 }; +const WORD DiskPatches[] = { 0x4010,0x4013,0x4016,0x401C,0x401F,0 }; /** Places in BIOS to be patched with ED FE C9 ***************/ -const word BIOSPatches[] = { 0x00E1,0x00E4,0x00E7,0x00EA,0x00ED,0x00F0,0x00F3,0 }; +const WORD BIOSPatches[] = { 0x00E1,0x00E4,0x00E7,0x00EA,0x00ED,0x00F0,0x00F3,0 }; /** Screen Mode Handlers [number of screens + 1] *************/ const void (*RefreshLine[MAXSCREEN+2])(byte Y) = @@ -278,9 +276,20 @@ static unsigned char linebuffer[WIDTH]; char *Disks[2][MAXDISKS+1]; /* Disk names for each drive */ -extern void * loc_Malloc(int size); - - +//#include +//EXTMEM static unsigned char MemPool[4*1024*1024]; +//static unsigned int ind=0; +/* +static void * loc_Malloc(int size) { + void * pt = emu_Malloc(size); + if (pt == NULL) { + void * pt = &MemPool[ind]; + ind += (size+3)&0xfffffffc; + emu_printf("EXTMEM allocation"); + } + return(pt); +} +*/ void emu_KeyboardOnDown(int keymodifer, int key) { } @@ -323,7 +332,7 @@ void msx_Input(int click) { static int SoundRate = 0; -static int MasterVolume = 200; +static int MasterVolume = 255; static int MasterSwitch = (1<>16; - I=I<-128? -128:I>127? 127:I; - //Buf[J]=AUDIO_CONV(I); + I=(Wave[J]*MasterVolume)>>12; //(256*16) + //I=I<-32768? -32768:I>32767? 32767:I; + //Wave[J]=AUDIO_CONV(I); *dest++ = I; *dest++ = I; Wave[J]=0; @@ -669,12 +678,10 @@ void msx_Start(char * Cartridge) int *T,I,J,K; byte *P; - word A; + WORD A; //FILE *F; -#ifdef SOUND_PRESENT -#ifdef HAS_SND - emu_sndInit(); +#ifdef HAS_SND SndDriver.SetSound = DSetSound; SndDriver.Drum = DDrum; SndDriver.SetChannels = DSetChannels; @@ -690,8 +697,7 @@ void msx_Start(char * Cartridge) CH[J].Volume = 0; CH[J].Freq = 0; } - SoundRate = 22050; -#endif + SoundRate = 22050; #else #endif /* Zero everyting */ @@ -1189,11 +1195,11 @@ struct { byte Pos,Mask; } Keys[] = void msx_Step(void) { JoyState = 0; - if (k & MASK_JOY2_DOWN) JoyState|=0x02; - if (k & MASK_JOY2_UP) JoyState|=0x01; - if (k & MASK_JOY2_LEFT) JoyState|=0x04; - if (k & MASK_JOY2_RIGHT) JoyState|=0x08; - if (k & MASK_JOY2_BTN) JoyState|=0x10; + if ( (k & MASK_JOY2_DOWN) || (k & MASK_JOY1_DOWN) ) JoyState|=0x02; + if ( (k & MASK_JOY2_UP) || (k & MASK_JOY1_UP) ) JoyState|=0x01; + if ( (k & MASK_JOY2_LEFT) || (k & MASK_JOY1_LEFT) ) JoyState|=0x04; + if ( (k & MASK_JOY2_RIGHT) || (k & MASK_JOY1_RIGHT) ) JoyState|=0x08; + if ( (k & MASK_JOY2_BTN) || (k & MASK_JOY1_BTN) ) JoyState|=0x10; if (k & MASK_KEY_USER2) JoyState|=0x20; if (hk != 0) { @@ -1216,7 +1222,7 @@ void msx_Step(void) { void SND_Process(void *stream, int len) { //psg_update(stream, 0, len); - mixaudio(stream, len); + mixaudio(stream, len/2); } @@ -1981,7 +1987,7 @@ static void RefreshLineTx80(register byte Y) /** made inlined to speed things up. **/ /*************************************************************/ #ifndef FMSX -byte RdZ80(word A) +byte RdZ80(WORD A) { if(A!=0xFFFF) return(RAM[A>>13][A&0x1FFF]); else return(PSL[3]==3? ~SSLReg:RAM[7][0x1FFF]); @@ -1992,7 +1998,7 @@ byte RdZ80(word A) /** Z80 emulation calls this function to write byte V to **/ /** address A of Z80 address space. **/ /*************************************************************/ -void WrZ80(word A,byte V) +void WrZ80(WORD A,byte V) { if(A!=0xFFFF) { @@ -2010,7 +2016,7 @@ void WrZ80(word A,byte V) /** Z80 emulation calls this function to read a byte from **/ /** a given I/O port. **/ /*************************************************************/ -byte InZ80(word Port) +byte InZ80(WORD Port) { /* MSX only uses 256 IO ports */ Port&=0xFF; @@ -2164,7 +2170,7 @@ case 0xA2: /* PSG input port */ /** Z80 emulation calls this function to write byte V to a **/ /** given I/O port. **/ /*************************************************************/ -void OutZ80(word Port,byte Value) +void OutZ80(WORD Port,byte Value) { register byte I,J,K; @@ -2237,7 +2243,7 @@ case 0x99: /* VDP Address Latch */ case 0x00: case 0x40: /* Set the VRAM access address */ - VAddr=(((word)Value<<8)+ALatch)&0x3FFF; + VAddr=(((WORD)Value<<8)+ALatch)&0x3FFF; /* WKey=1 when VDP set for writing into VRAM */ WKey=Value&0x40; /* When set for reading, perform first read */ @@ -2376,7 +2382,7 @@ case 0xFF: /* Mapper page at C000h */ /** Switch ROM Mapper pages. This function is supposed to **/ /** be called when ROM page registers are written to. **/ /*************************************************************/ -void MapROM(register word A,register byte V) +void MapROM(register WORD A,register byte V) { byte I,J,K,*P; @@ -2617,7 +2623,7 @@ byte *LoadROM(const char *Name,int Size,byte *Buf) if (Size<=0) return (0); - P=Buf? Buf:loc_Malloc(Size); + P=Buf? Buf:emu_Malloc(Size); //loc_Malloc(Size); emu_LoadFile(Name, P, Size); /* Add a new chunk to free */ @@ -2647,7 +2653,7 @@ byte *LoadROM(const char *Name,int Size,byte *Buf) } /* Allocate memory */ - P=Buf? Buf:loc_Malloc(Size); + P=Buf? Buf:emu_Malloc(size); //loc_Malloc(Size); if(!P) { fclose(F); @@ -2736,17 +2742,22 @@ int LoadCart(const char *Name,int Slot) /* Length must be a multiple of 8kB */ /* Flat 64kB ROM must be 40..64kB */ - //if(Size&0x1FFF) { emu_printf("failed");return(0); } - //if(ROM64&&(Size<0xA000)) { emu_printf("failed");return(0); } - //if(ROM64&&(Size>0x10000)) { emu_printf("failed");return(0); } + if(Size&0x1FFF) { emu_printf("failed");return(0); } + if(ROM64&&(Size<0xA000)) { emu_printf("failed");return(0); } + if(ROM64&&(Size>0x10000)) { emu_printf("failed");return(0); } /* Show ROM type and size */ - //if(Verbose) + //if(Verbose) // printf // ( // "%dkB %s ROM...",C1/1024, // !ROM64&&(C1>0x8000)? ROMNames[Slot? ROMTypeB:ROMTypeA]:"NORMAL" // ); + + emu_printf("size"); + emu_printi(C1/1024); + emu_printf(!ROM64&&(C1>0x8000)? ROMNames[Slot? ROMTypeB:ROMTypeA]:"NORMAL"); + /* Compute size in 8kB pages */ Size >>= 13; @@ -2757,9 +2768,16 @@ int LoadCart(const char *Name,int Slot) /* Assign ROMMask for MegaROMs */ ROMMask[Slot]=!ROM64&&(Size>4)? C3-1:0x00; + emu_printi(C3*0x2000); + + /* Allocate space for the ROM */ - ROMData[Slot]=loc_Malloc(C3*0x2000); - if(!ROMData[Slot]) { emu_printf("failed");return(0); } + ROMData[Slot]=emu_SMalloc(C3*0x2000); //&MemPool[0]; + + emu_printf("JJJJJJJJ rom loaded"); + + + if(!ROMData[Slot]) { emu_printf("failed 2");return(0); } Chunks[CCount++]=ROMData[Slot]; /* Try loading ROM */ @@ -2853,7 +2871,7 @@ int LoadCart(const char *Name,int Slot) /** Set or reset IRQ. Returns IRQ vector assigned to **/ /** CPU.IRequest. When upper bit of IRQ is 1, IRQ is reset. **/ /*************************************************************/ -word SetIRQ(register byte IRQ) +WORD SetIRQ(register byte IRQ) { if(IRQ&0x80) IRQPending&=IRQ; else IRQPending|=IRQ; CPU.IRequest=IRQPending? INT_IRQ:INT_NONE; @@ -3055,8 +3073,8 @@ byte RTCIn(register byte R) /** Refresh screen, check keyboard and sprites. Call this **/ /** function on each interrupt. **/ /*************************************************************/ -word LoopZ80(register Z80 *R, int * ras) -//word LoopZ80(Z80 *R) +WORD LoopZ80(register Z80 *R, int * ras) +//WORD LoopZ80(Z80 *R) { static byte BFlag=0; static byte BCount=0; @@ -3190,7 +3208,7 @@ word LoopZ80(register Z80 *R, int * ras) if(ModeYAE) RefreshLine10(ScanLine); else RefreshLine12(ScanLine); - emu_DrawLine(&linebuffer[0], WIDTH , HEIGHT, ScanLine+FirstLine); + emu_DrawLinePal16(&linebuffer[0], WIDTH , HEIGHT, ScanLine+FirstLine); } /* Keyboard, sound, and other stuff always runs at line 192 */ @@ -3236,7 +3254,7 @@ word LoopZ80(register Z80 *R, int * ras) /*************************************************************/ void CheckSprites(void) { - register word LS,LD; + register WORD LS,LD; register byte DH,DV,*PS,*PD,*T; byte I,J,N,M,*S,*D; @@ -3265,8 +3283,8 @@ void CheckSprites(void) if(DH>240) { DH=256-DH;T=PS;PS=PD;PD=T; } while(DV<16) { - LS=((word)*PS<<8)+*(PS+16); - LD=((word)*PD<<8)+*(PD+16); + LS=((WORD)*PS<<8)+*(PS+16); + LD=((WORD)*PD<<8)+*(PD+16); if(LD&(LS>>DH)) break; else { DV++;PS++;PD++; } } @@ -3339,16 +3357,3 @@ int GuessROM(const byte *Buf,int Size) /* Return the most likely mapper type */ return(I); } - -#include -EXTMEM static unsigned char MemPool[4*1024*1024]; -static unsigned int ind=0; - -void * loc_Malloc(int size) { - //void * pt = emu_Malloc(size); - //if (pt == NULL) { - void * pt = &MemPool[ind]; - ind += (size+3)&0xfffffffc; - //} - return(pt); -} diff --git a/MCUME_teensy41/teensymsx/fmsx.h b/MCUME_teensy41/teensymsx/wrapemu.h similarity index 64% rename from MCUME_teensy41/teensymsx/fmsx.h rename to MCUME_teensy41/teensymsx/wrapemu.h index 6b171db..d2bf9a2 100644 --- a/MCUME_teensy41/teensymsx/fmsx.h +++ b/MCUME_teensy41/teensymsx/wrapemu.h @@ -1,5 +1,10 @@ +#ifdef __cplusplus +extern "C" { +#endif extern void msx_Init(void); extern void msx_Step(void); extern void msx_Start(char * filename); extern void msx_Input(int click); - +#ifdef __cplusplus +} +#endif diff --git a/MCUME_teensy41/teensynofrendo/bitmap.c b/MCUME_teensy41/teensynofrendo/bitmap.c index 2e92abf..fd07c9f 100644 --- a/MCUME_teensy41/teensynofrendo/bitmap.c +++ b/MCUME_teensy41/teensynofrendo/bitmap.c @@ -65,7 +65,8 @@ static bitmap_t *_make_bitmap(uint8 *data_addr, bool hw, int width, */ //printf("setting up bitmap %d\n",(int)bitmap); for (i = 0; i < height; i++) { - bitmap->line[i] = emu_LineBuffer(i); + + bitmap->line[i] = emu_Malloc(pitch); //emu_LineBuffer(i); } return bitmap; diff --git a/MCUME_teensy41/teensynofrendo/emuapi.cpp b/MCUME_teensy41/teensynofrendo/emuapi.cpp index c367cb0..e128cca 100644 --- a/MCUME_teensy41/teensynofrendo/emuapi.cpp +++ b/MCUME_teensy41/teensynofrendo/emuapi.cpp @@ -5,25 +5,31 @@ extern "C" { #include "iopins.h" } -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#else -#include "tft_t_dma.h" -#endif +#include -#ifdef HAS_USBKEY +#ifdef HAS_USB #include "USBHost_t36.h" // Read this header first for key info USBHost myusb; USBHub hub1(myusb); +#ifdef HAS_USBKEY KeyboardController keyboard1(myusb); USBHIDParser hid1(myusb); MouseController mouse1(myusb); +#endif +#ifdef HAS_USBMIDI MIDIDevice midi1(myusb); #endif +#ifdef HAS_USBJOY +#define COUNT_JOYSTICKS 4 +JoystickController joysticks[COUNT_JOYSTICKS](myusb); +#endif +#endif static bool emu_writeConfig(void); static bool emu_readConfig(void); static bool emu_eraseConfig(void); +static bool emu_writeGfxConfig(char * display_type); +static int emu_readGfxConfig(void); static bool mouseDetected = false; static bool keyboardDetected = false; @@ -34,12 +40,13 @@ static File file; #define MAX_FILES 64 #define AUTORUN_FILENAME "autorun.txt" +#define GFX_CFG_FILENAME "gfxmode.txt" -#define MAX_FILENAME_SIZE 24 +#define MAX_FILENAME_SIZE 34 #define MAX_MENULINES 9 #define TEXT_HEIGHT 16 #define TEXT_WIDTH 8 -#define MENU_FILE_XOFFSET (6*TEXT_WIDTH) +#define MENU_FILE_XOFFSET (2*TEXT_WIDTH) #define MENU_FILE_YOFFSET (2*TEXT_HEIGHT) #define MENU_FILE_W (MAX_FILENAME_SIZE*TEXT_WIDTH) #define MENU_FILE_H (MAX_MENULINES*TEXT_HEIGHT) @@ -53,7 +60,8 @@ static File file; #define MENU_VGA_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) #define MENU_VGA_YOFFSET (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37) -extern TFT_T_DMA tft; +#include "t4_dsp.h" +T4_DSP tft; static int nbFiles=0; static int curFile=0; @@ -65,6 +73,8 @@ static char selected_filename[MAX_FILENAME_SIZE]=""; static char second_selected_filename[MAX_FILENAME_SIZE]=""; static bool menuRedraw=true; static bool autorun=false; +static bool vgahires=false; + static const unsigned short * keys; #ifdef TEECOMPUTER @@ -158,6 +168,29 @@ void emu_Free(void * pt) free(pt); } +#define SMEMPOOL (0x800000) +EXTMEM static unsigned char slowmem[SMEMPOOL]; +static int slowmempt = 0; + +void * emu_SMalloc(unsigned int size) +{ + void * mem = (void*)&slowmem[slowmempt]; + slowmempt += size; + + if ( slowmempt > SMEMPOOL ) { + mem = NULL; + emu_printf("failure to allocate slow"); + } + else { + emu_printf("could allocate slow static "); + emu_printf(size); + } + return mem; +} + +void emu_SFree(void * pt) +{ +} /******************************** * Input and keyboard ********************************/ @@ -329,6 +362,12 @@ int emu_ReadKeys(void) #endif if ( row & 0x02 ) retval |= MASK_JOY2_BTN; + +#ifdef EXTPAD + if ( sh_pressed ) retval |= MASK_KEY_USER3; + if ( fn_pressed ) retval |= MASK_KEY_USER1; + digitalWrite(KLED, 0); +#else // Handle LED flash uint32_t time_ms=millis(); if ((time_ms-last_t_ms) > 100) { @@ -412,8 +451,9 @@ int emu_ReadKeys(void) if ( key_fn ) retval |= MASK_KEY_USER2; if ( ( key_fn ) && (keymatrix[4] == 0x10 )) retval |= MASK_KEY_USER1; +#endif - if ( (key_fn) && (key_sh) ) + if ( (fn_pressed) && (sh_pressed) ) #else if ( ((retval & (MASK_KEY_USER1+MASK_KEY_USER2)) == (MASK_KEY_USER1+MASK_KEY_USER2)) || (retval & MASK_KEY_USER4 ) ) @@ -453,8 +493,10 @@ int emu_ReadKeys(void) while (true) { ; } -#endif +#endif } + + emu_GetJoystick(); return (retval); } @@ -607,7 +649,7 @@ int emu_setKeymap(int index) { } int emu_GetMouse(int *x, int *y, int *buts) { -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBKEY) if (mouse1.available()) { *buts = mouse1.getButtons(); *x = mouse1.getMouseX(); @@ -620,7 +662,23 @@ int emu_GetMouse(int *x, int *y, int *buts) { return 0; } -#ifdef HAS_USBKEY +int emu_GetJoystick(void) { +#if defined(HAS_USB) && (HAS_USBJOY) + for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) { + if (joysticks[joystick_index].available()) { + uint64_t axis_mask = joysticks[joystick_index].axisMask(); + uint64_t axis_changed_mask = joysticks[joystick_index].axisChangedMask(); + uint32_t buttons = joysticks[joystick_index].getButtons(); + Serial.printf("Joystick(%d): buttons = %x", joystick_index, buttons); + Serial.println(); + } + } + return 1; +#endif + return 0; +} + +#if defined(HAS_USB) && (HAS_USBKEY) void OnPress(auto key) { keyboardDetected = true; @@ -764,7 +822,7 @@ int emu_KeyboardDetected(void) { return (keyboardDetected?1:0); } -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) static unsigned char midiBuffer[16]; static unsigned char midiLastCmd=0; static int midiDataCnt=0; @@ -772,8 +830,7 @@ static int midiCmdNbParam=0; #endif void emu_MidiOnDataReceived(unsigned char value) { - -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) //Serial.println(value, HEX); //10000000 = 128 = note off //10010000 = 144 = note on @@ -941,6 +998,7 @@ void emu_MidiOnDataReceived(unsigned char value) { /******************************** * Menu file loader UI ********************************/ +#ifdef FILEBROWSER static int readNbFiles(void) { int totalFiles = 0; @@ -970,8 +1028,6 @@ static int readNbFiles(void) { return totalFiles; } - - void backgroundMenu(void) { menuRedraw=true; tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00)); @@ -981,11 +1037,13 @@ void backgroundMenu(void) { int handleMenu(uint16_t bClick) { if (autorun) { + toggleMenu(false); + menuRedraw=false; return (ACTION_RUN1); } int action = ACTION_NONE; - if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) ) { + if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) || ( bClick & MASK_KEY_USER2 ) ) { char newpath[MAX_FILENAME_PATH]; strcpy(newpath, selection); strcat(newpath, "/"); @@ -996,17 +1054,31 @@ int handleMenu(uint16_t bClick) File file = SD.open(selection); if (file.isDirectory()) { curFile = 0; - nbFiles = readNbFiles(); + nbFiles = readNbFiles(); + menuRedraw=true; } - else { - action = ACTION_RUN1; + else + { #ifdef TEECOMPUTER - if (key_extmode) { + if ( (key_extmode) || ( key_sh) ) { emu_writeConfig(); } + if ( tft.getMode() < MODE_VGA_320x240) { + if ( bClick & MASK_KEY_USER2 ) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + } + //emu_SwapJoysticks(0); #endif + toggleMenu(false); + menuRedraw=false; + return (ACTION_RUN1); } - menuRedraw=true; } else if ( bClick & MASK_KEY_USER1 ) { menuRedraw=true; @@ -1015,19 +1087,14 @@ int handleMenu(uint16_t bClick) strcat(second_selection, "/"); strcat(second_selection, second_selected_filename); action = ACTION_RUN2; - } - else if ( bClick & MASK_KEY_USER2 ) { - menuRedraw=true; - //action = ACTION_RUN3; - emu_SwapJoysticks(0); - } + } else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) { if (curFile!=0) { menuRedraw=true; curFile--; } } - else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { + else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { if ((curFile-9)>=0) { menuRedraw=true; curFile -= 9; @@ -1042,7 +1109,7 @@ int handleMenu(uint16_t bClick) menuRedraw=true; } } - else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { + else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { if ((curFile<(nbFiles-9)) && (nbFiles)) { curFile += 9; menuRedraw=true; @@ -1099,12 +1166,12 @@ int handleMenu(uint16_t bClick) return (action); } -bool menuActive(void) +int menuActive(void) { - return (menuOn); + return (menuOn?1:0); } -void toggleMenu(bool on) { +void toggleMenu(int on) { if (on) { menuOn=true; backgroundMenu(); @@ -1122,7 +1189,7 @@ char * menuSecondSelection(void) { return (second_selection); } - +#endif /******************************** * OSKB handling @@ -1140,8 +1207,9 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) char c[4] = {' ',0,' ',0}; const char * cpt = str; int i=0; - int fb_width,fb_height; - tft.get_frame_buffer_size(&fb_width, &fb_height); + int fb_width,fb_height,fbstride; + + fbstride = tft.get_frame_buffer_size(&fb_width, &fb_height); int ypos = (bottom?(fb_height-2*8):0); int line = row + (bottom?2:0); while ((c[1] = *cpt++)) @@ -1150,7 +1218,7 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0); else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff); if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff); - tft.drawTextNoDma(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); + tft.drawText(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); i++; } } @@ -1248,7 +1316,7 @@ int handleOSKB(void) { return retval; } -void toggleOSKB(bool forceon) { +void toggleOSKB(int forceon) { if (forceon) { oskbOn = true; drawOSKB(); @@ -1332,6 +1400,17 @@ int emu_FileRead(void * buf, int size, int handler) #endif } +int emu_FileWrite(void * buf, int size, int handler) +{ +// emu_printf("emu_FileWrite"); +// emu_printi(handler); +#ifdef HCFH + return (file.write(buf, size)); +#else + return (getFileHandler(handler).write(buf, size)); +#endif +} + int emu_FileGetc(int handler) { // emu_printf("FileGetc"); // emu_printi(handler); @@ -1404,6 +1483,9 @@ unsigned int emu_FileSize(const char * filepath) emu_printf(filesize); lofile.close(); } + else { + emu_printf("filesize failed"); + } return(filesize); } @@ -1489,6 +1571,48 @@ static bool emu_eraseConfig(void) SD.remove (ROMSDIR "/" AUTORUN_FILENAME); } +static bool emu_writeGfxConfig(char * display_type) +{ + bool retval = false; + SD.remove ("/" GFX_CFG_FILENAME); + if (strcmp(display_type, "VGA")) { + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(display_type, strlen(display_type)) != strlen(display_type)) { + emu_printf("GFX config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + } + return retval; +} + +#define CFG_VGA 0 +#define CFG_ILI 1 +#define CFG_ST 2 + +static int emu_readGfxConfig(void) +{ + int retval = CFG_VGA; // No file = VGA + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + if (filesize == 2) // "ST" + { + retval = CFG_ST; + } + else if (filesize == 3) // "ILI" + { + retval = CFG_ILI; + } + lofile.close(); + } + return retval; +} + /******************************** * File IO compatibility ********************************/ @@ -1670,62 +1794,249 @@ FRESULT f_mkdir (const char* path) /******************************** - * Initialization + * GFX wrapper ********************************/ -void emu_init(void) +static unsigned short palette16[PALETTE_SIZE]; +static IntervalTimer myTimer; +volatile boolean vbl=true; +volatile boolean vgatimervsync=false; +static void (*vblCallback)(void) = nullptr; +static int skip=0; + +static void vblCount() { + if (vbl) { + vbl = false; + } else { + vbl = true; + } +} + +void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) +{ + if (index= MODE_VGA_320x240 ) { + if (vgatimervsync) { + while (vbl==vb) {}; + } + else { + tft.waitSync(); + } + } + else { + while (vbl==vb) {}; + } + if (vblCallback != nullptr) { + vblCallback(); + } +} + +void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride) +{ + if (skip == 0) { + tft.writeScreenPal(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); + } +} +void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLinePal(width,height,line, VBuf, palette16); + } +} + +void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine(width,height,line, VBuf); + } +} + +void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine8(width,height,line, VBuf, palette16); + } +} + +int emu_IsVga(void) +{ + return (tft.getMode() >= MODE_VGA_320x240?1:0); +} + +int emu_IsVgaHires(void) +{ + return (tft.getMode() >= MODE_VGA_640x240?1:0); +} + +int emu_FrameSkip(void) +{ + return skip; +} + + +/******************************** + * AUDIO wrapper +********************************/ +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +AudioPlaySystem mymixer; + +void emu_sndInit() { + Serial.println("sound init"); + mymixer.begin_audio(256, mymixer.snd_Mixer); + mymixer.start(); +} + +void emu_sndPlaySound(int chan, int volume, int freq) +{ + if (chan < 6) { + mymixer.sound(chan, freq, volume); + } + /* + Serial.print(chan); + Serial.print(":" ); + Serial.print(volume); + Serial.print(":" ); + Serial.println(freq); + */ +} + +void emu_sndPlayBuzz(int size, int val) { + mymixer.buzz(size,val); + //Serial.print((val==1)?1:0); + //Serial.print(":"); + //Serial.println(size); +} +#endif + +/******************************** + * Initialization +********************************/ +void emu_init(int hires) { Serial.begin(115200); + vgahires = hires; -#ifdef HAS_USBKEY +#ifdef HAS_USB myusb.begin(); +#ifdef HAS_USBKEY keyboard1.attachPress(OnPress); keyboard1.attachRelease(OnRelease); #endif +#endif - while (!SD.begin(SD_CS)) +#ifdef FILEBROWSER + if (!SD.begin(SD_CS)) { - Serial.println("SD begin failed, retrying..."); - delay(1000); + Serial.println("No SD card detected"); } strcpy(selection,ROMSDIR); - FileHandlersInit(); - nbFiles = readNbFiles(); - - Serial.print("SD initialized, files found: "); Serial.println(nbFiles); +#endif emu_InitJoysticks(); #ifdef SWAP_JOYSTICK - joySwapped = true; + joySwapped = true; #else - joySwapped = false; + joySwapped = false; #endif -#ifdef TEECOMPUTER -#ifndef HAS_T4_VGA - tft.flipscreen(false); -#endif -#endif int keypressed = emu_ReadKeys(); +#ifdef HAS_T4_VGA + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } +#else + int gfx_mode = CFG_VGA; // default +#ifdef FILEBROWSER + gfx_mode = emu_readGfxConfig(); +#endif + // Force VGA if UP pressed + if (keypressed & MASK_JOY2_UP) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("VGA"); +#endif + gfx_mode = CFG_VGA; + } + else { + if (keypressed & MASK_JOY2_LEFT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ST"); +#endif + gfx_mode = CFG_ST; + } + else if (keypressed & MASK_JOY2_RIGHT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ILI"); +#endif + gfx_mode = CFG_ILI; + } + } + if (gfx_mode == CFG_VGA) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + else + { + tft.begin(gfx_mode == CFG_ILI?MODE_TFTILI_320x240:MODE_TFTST_320x240); + } +#endif + if (keypressed & MASK_JOY2_DOWN) { tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) ); tft.drawTextNoDma(64,48, (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); +#ifdef FILEBROWSER emu_eraseConfig(); delay(1000); +#endif } else { +#ifdef FILEBROWSER if (emu_readConfig()) { autorun = true; } +#endif } +#ifdef FILEBROWSER toggleMenu(true); +#endif } -void emu_start(void) +void emu_start(int vblms, void * callback, int forcetimervsync) { + vgatimervsync = forcetimervsync?true:false; + tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); + tft.startRefresh(); + if (callback != nullptr) { + vblCallback = callback; + } + + myTimer.begin(vblCount, vblms); +#ifdef HAS_SND + emu_sndInit(); +#endif usbnavpad = 0; } diff --git a/MCUME_teensy41/teensynofrendo/emuapi.h b/MCUME_teensy41/teensynofrendo/emuapi.h index 416fbae..5dd6130 100644 --- a/MCUME_teensy41/teensynofrendo/emuapi.h +++ b/MCUME_teensy41/teensynofrendo/emuapi.h @@ -2,126 +2,14 @@ #define EMUAPI_H #include "platform_config.h" - -#define CUSTOM_SND 1 -//#define TIMER_REND 1 - -#define EXTRA_HEAP 0x10 - -// Title: < > -#define TITLE " NES Emulator" -#define ROMSDIR "nes" - -#define emu_Init(ROM) {nes_Start(ROM); nes_Init(); } -#define emu_Step(x) { nes_Step(); } -#define emu_Input(x) { nes_Input(x); } - -#define MAX_FILENAME_PATH 64 -#define NB_FILE_HANDLER 4 -#define PALETTE_SIZE 256 -#define VID_FRAME_SKIP 0x0 -#define TFT_VBUFFER_YCROP 0 -#define SINGLELINE_RENDERING 1 - -#define R32(rgb) ((rgb>>16)&0xff) -#define G32(rgb) ((rgb>>8)&0xff) -#define B32(rgb) (rgb & 0xff) +#include "emucfg.h" #define ACTION_NONE 0 -#define ACTION_MAXKBDVAL 16 -#define ACTION_EXITKBD 128 -#define ACTION_RUN1 129 -#define ACTION_RUN2 130 -#define ACTION_RUN3 131 - -#ifdef KEYMAP_PRESENT - -#define keylables_map0_0 (char *)"qwertyuiop\x1a" -#define keylables_map0_1 (char *)" asdfghjkl\x19" -#define keylables_map0_2 (char *)" zxcvbnm,.;/" -#define keylables_map0_3 (char *)" +\x10-" -const unsigned short key_map0[] = { - 'q','w','e','r','t','y','u','i','o','p',157, //lowecase - 0,'a','s','d','f','g','h','j','k','l',0x0D, - 0,'z','x','c','v','b','n','m',',','.',';','/', - 145,157,29,17, - 0,'+',' ','-' - }; - -#define keylables_map1_0 (char *)"QWERTYUIOP@" -#define keylables_map1_1 (char *)" ASDFGHJKL\x19" -#define keylables_map1_2 (char *)" ZXCVBNM<>:?" -#define keylables_map1_3 (char *)" =\x10_" -const unsigned short key_map1[] = { - 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase - 0,'A','S','D','F','G','H','J','K','L',0x0D, - 0,'Z','X','C','V','B','N','M','<','>',':','?', - 145,157,29,17, - 0,'=',' ','_' - }; - -#define keylables_map2_0 (char *)"!\"#$%^&*()@" -#define keylables_map2_1 (char *)" |\\[]{} " -#define keylables_map2_2 (char *)" <>:?" -#define keylables_map2_3 (char *)" =\x10_" -const unsigned short key_map2[] = { - '!','"','#','$','%','^','&','*','(',')','@', // shiftothers - 0, '|','\\','[',']','{','}','\'',0,0,0, - 0, 0,0,0,0,0,0,0,'<','>',':','?', - 0,0,0,0, - 0,'=',' ','_' - }; - -#define keylables_map3_0 (char *)"1234567890 " -#define keylables_map3_1 (char *)" " -#define keylables_map3_2 (char *)" " -#define keylables_map3_3 (char *)" " - -const unsigned short key_map3[] = { - '1','2','3','4','5','6','7','8','9','0',0, // digit keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map4_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " -#define keylables_map4_1 (char *)" " -#define keylables_map4_2 (char *)" " -#define keylables_map4_3 (char *)" " - -const unsigned short key_map4[] = { - 133,134,135,136,137,138,139,140,0,0,0, // function keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map5_0 (char *)" " -#define keylables_map5_1 (char *)" " -#define keylables_map5_2 (char *)" " -#define keylables_map5_3 (char *)" " - -const unsigned short key_map5[] = { - 0,0,0,0,0,0,0,0,0,0,0, // extra keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -const unsigned short matkeys[] = { - 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 - 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 - 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 - 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN - 0x510,0x010,0x110,0x310, // row 4 - }; - -#endif - +#define ACTION_RUN1 1 +#define ACTION_RUN2 2 +#define FORCE_VGATIMERVSYNC 1 +#define SUPPORT_HIRES 1 #define MASK_JOY2_RIGHT 0x0001 #define MASK_JOY2_LEFT 0x0002 @@ -138,22 +26,25 @@ const unsigned short matkeys[] = { #define MASK_JOY1_BTN 0x1000 #define MASK_KEY_USER4 0x2000 +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) #ifdef __cplusplus extern "C" { +extern void emu_init(int hires=0); +extern void emu_start(int vblms, void * callback, int forcetimervsync=0); #endif - -extern void emu_init(void); -extern void emu_start(void); extern void emu_printf(const char * text); extern void emu_printi(int val); extern void emu_printh(int val); extern void * emu_Malloc(unsigned int size); extern void * emu_MallocI(unsigned int size); extern void emu_Free(void * pt); +extern void * emu_SMalloc(unsigned int size); +extern void emu_SFree(void * pt); extern int emu_FileOpen(const char * filepath, const char * mode); extern int emu_FileRead(void * buf, int size, int handler); +extern int emu_FileWrite(void * buf, int size, int handler); extern int emu_FileGetc(int handler); extern int emu_FileSeek(int handler, int seek, int origin); extern int emu_FileTell(int handler); @@ -164,24 +55,23 @@ extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size); extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek); extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index); -extern void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride); -extern void emu_DrawLine(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line); extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line); +extern void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride); extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line); -extern void emu_CopyLine(int width, int height, int ysrc, int ydst); extern void emu_DrawVsync(void); extern int emu_FrameSkip(void); -extern void * emu_LineBuffer(int line); -extern void emu_tweakVideo(int shiftdelta, int numdelta, int denomdelta); +extern int emu_IsVga(void); +extern int emu_IsVgaHires(void); -extern bool menuActive(void); +extern int menuActive(void); extern char * menuSelection(void); extern char * menuSecondSelection(void); -extern void toggleMenu(bool on); +extern void toggleMenu(int on); extern int handleMenu(unsigned short bClick); extern int handleOSKB(void); -extern void toggleOSKB(bool forceon); +extern void toggleOSKB(int forceon); extern void emu_InitJoysticks(void); extern int emu_SwapJoysticks(int statusOnly); @@ -190,6 +80,7 @@ extern int emu_ReadKeys(void); extern int emu_GetPad(void); extern int emu_GetMouse(int *x, int *y, int *buts); extern int emu_MouseDetected(void); +extern int emu_GetJoystick(void); extern int emu_KeyboardDetected(void); extern int emu_ReadAnalogJoyX(int min, int max); extern int emu_ReadAnalogJoyY(int min, int max); diff --git a/MCUME_teensy41/teensynofrendo/emucfg.h b/MCUME_teensy41/teensynofrendo/emucfg.h new file mode 100644 index 0000000..357cc72 --- /dev/null +++ b/MCUME_teensy41/teensynofrendo/emucfg.h @@ -0,0 +1,116 @@ +#ifndef EMUCFG_H +#define EMUCFG_H + + +#include "wrapemu.h" + +// Title: < > +#define TITLE " NES Emulator" +#define ROMSDIR "nes" + +#define emu_Init(ROM) {nes_Start(ROM); nes_Init(); } +#define emu_Step(x) { nes_Step(); } +#define emu_Input(x) { nes_Input(x); } + +#define MAX_FILENAME_PATH 64 +#define NB_FILE_HANDLER 4 + +#define PALETTE_SIZE 256 +#define VID_FRAME_SKIP 0x0 +#define TFT_VBUFFER_YCROP 0 +#define SINGLELINE_RENDERING 1 +#define CUSTOM_SND 1 +//#define TIMER_REND 1 +//#define EXTPAD 1 +#define EXTRA_HEAP 0x10 +#define FILEBROWSER 1 + + +#ifdef KEYMAP_PRESENT + +#define keylables_map0_0 (char *)"qwertyuiop\x1a" +#define keylables_map0_1 (char *)" asdfghjkl\x19" +#define keylables_map0_2 (char *)" zxcvbnm,.;/" +#define keylables_map0_3 (char *)" +\x10-" +const unsigned short key_map0[] = { + 'q','w','e','r','t','y','u','i','o','p',157, //lowecase + 0,'a','s','d','f','g','h','j','k','l',0x0D, + 0,'z','x','c','v','b','n','m',',','.',';','/', + 145,157,29,17, + 0,'+',' ','-' + }; + +#define keylables_map1_0 (char *)"QWERTYUIOP@" +#define keylables_map1_1 (char *)" ASDFGHJKL\x19" +#define keylables_map1_2 (char *)" ZXCVBNM<>:?" +#define keylables_map1_3 (char *)" =\x10_" +const unsigned short key_map1[] = { + 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase + 0,'A','S','D','F','G','H','J','K','L',0x0D, + 0,'Z','X','C','V','B','N','M','<','>',':','?', + 145,157,29,17, + 0,'=',' ','_' + }; + +#define keylables_map2_0 (char *)"!\"#$%^&*()@" +#define keylables_map2_1 (char *)" |\\[]{} " +#define keylables_map2_2 (char *)" <>:?" +#define keylables_map2_3 (char *)" =\x10_" +const unsigned short key_map2[] = { + '!','"','#','$','%','^','&','*','(',')','@', // shiftothers + 0, '|','\\','[',']','{','}','\'',0,0,0, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 0,0,0,0, + 0,'=',' ','_' + }; + +#define keylables_map3_0 (char *)"1234567890 " +#define keylables_map3_1 (char *)" " +#define keylables_map3_2 (char *)" " +#define keylables_map3_3 (char *)" " + +const unsigned short key_map3[] = { + '1','2','3','4','5','6','7','8','9','0',0, // digit keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map4_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " +#define keylables_map4_1 (char *)" " +#define keylables_map4_2 (char *)" " +#define keylables_map4_3 (char *)" " + +const unsigned short key_map4[] = { + 133,134,135,136,137,138,139,140,0,0,0, // function keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map5_0 (char *)" " +#define keylables_map5_1 (char *)" " +#define keylables_map5_2 (char *)" " +#define keylables_map5_3 (char *)" " + +const unsigned short key_map5[] = { + 0,0,0,0,0,0,0,0,0,0,0, // extra keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +const unsigned short matkeys[] = { + 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 + 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 + 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 + 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN + 0x510,0x010,0x110,0x310, // row 4 + }; + +#endif + +#endif diff --git a/MCUME_teensy41/teensynofrendo/nes_ppu.c b/MCUME_teensy41/teensynofrendo/nes_ppu.c index ac884ca..2a77102 100644 --- a/MCUME_teensy41/teensynofrendo/nes_ppu.c +++ b/MCUME_teensy41/teensynofrendo/nes_ppu.c @@ -1031,7 +1031,7 @@ static void ppu_renderscanline(bitmap_t *bmp, int scanline, bool draw_flag) ppu_fakeoam(scanline); if (draw_flag) - emu_DrawLine(buf, 256, 240, scanline); + emu_DrawLinePal16(buf, 256, 240, scanline); } diff --git a/MCUME_teensy41/teensynofrendo/platform_config.h b/MCUME_teensy41/teensynofrendo/platform_config.h index a27370c..914d152 100644 --- a/MCUME_teensy41/teensynofrendo/platform_config.h +++ b/MCUME_teensy41/teensynofrendo/platform_config.h @@ -4,13 +4,13 @@ #define TEECOMPUTER 1 #ifdef TEECOMPUTER -//#define ILI9341 1 -//#define ST7789 1 -//#define TFTSPI1 1 -#define HAS_T4_VGA 1 +#define TFTSPI1 1 +//#define HAS_T4_VGA 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 -#define INVX 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 #define PT8211 1 #else @@ -19,7 +19,11 @@ //#define INVX 1 #define INVY 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 +#define PT8211 1 #endif diff --git a/MCUME_teensy41/teensynofrendo/t4_dsp.cpp b/MCUME_teensy41/teensynofrendo/t4_dsp.cpp new file mode 100644 index 0000000..43301fa --- /dev/null +++ b/MCUME_teensy41/teensynofrendo/t4_dsp.cpp @@ -0,0 +1,1774 @@ +/* + TFT/VGA driver + DMA TFT driver based on C64 ILI9341 dma driver from Frank Bösing, 2017 +*/ + +#include "T4_DSP.h" + +#include +#include + +#include "font8x8.h" + +// TFT constants and variables +#define TFT_LINEARINT 1 +#define LINEARINT_HACK 1 +#define DMA_LINES_PER_BLOCK 64 +#define DMA_NUM_SETTINGS 4 + +#define TFT_SWRESET 0x01 +#define TFT_SLPOUT 0x11 +#define TFT_INVON 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_MADCTL 0x36 +#define TFT_PIXFMT 0x3A +#define TFT_MADCTL_MY 0x80 +#define TFT_MADCTL_MX 0x40 +#define TFT_MADCTL_MV 0x20 +#define TFT_MADCTL_ML 0x10 +#define TFT_MADCTL_RGB 0x00 +#define TFT_MADCTL_BGR 0x08 +#define TFT_MADCTL_MH 0x04 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) +//#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) +//#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) +//#define R16(rgb) ((rgb>>8)&0xf8) +//#define G16(rgb) ((rgb>>3)&0xfc) +//#define B16(rgb) ((rgb<<3)&0xf8) + +// LPSPI4 = SPI0 in Teensy 4.0 +// LPSPI3 = SPI1 in Teensy 4.0 +// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) + +#ifdef TFTSPI1 +#define SPI SPI1 +#define LPSPIP_TDR LPSPI3_TDR +#define LPSPIP_CR LPSPI3_CR +#define LPSPIP_CFGR1 LPSPI3_CFGR1 +#define LPSPIP_TCR LPSPI3_TCR +#define LPSPIP_DER LPSPI3_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX +#else +#define LPSPIP_TDR LPSPI4_TDR +#define LPSPIP_CR LPSPI4_CR +#define LPSPIP_CFGR1 LPSPI4_CFGR1 +#define LPSPIP_TCR LPSPI4_TCR +#define LPSPIP_DER LPSPI4_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX +#endif + +#define SPICLOCK 60000000 +#define SPI_MODE SPI_MODE0 + +// VGA constants and macros +typedef uint8_t vga_pixel; +#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) + +static DMASetting dmasettings[DMA_NUM_SETTINGS]; +static DMAChannel dmatx; +static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K +static volatile uint8_t rstop = 0; +static volatile bool cancelled = false; +static volatile uint8_t curTransfer = 0; +static uint8_t nbTransfer = 0; +static uint16_t * tft_buffer; +static int tft_width; +static int tft_height; +static int tft_stride; + +#define DELAY_MASK 0x80 +PROGMEM static const uint8_t init_commands[] = { + 1+DELAY_MASK, TFT_SWRESET, 150, + 1+DELAY_MASK, TFT_SLPOUT, 255, + 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, + 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, + 1, TFT_INVON, + 1, TFT_DISPON, + 0 +}; + +// VGA constants and variables +// Objective: +// generates VGA signal fully in hardware with as little as possible CPU help + +// Principle: +// QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) +// 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate +// RGB out, combined to create 8bits(/12bits) output. + +// Note: +// - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels +// - experimental resolution: 352x240,352x480 +// - experimental resolution: 512x240,512x480 (not stable) +// - video memory is allocated using malloc in T4 heap +// - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing +// but tried to be compensated by pixel shifting +// - Default is 8bits RRRGGGBB (332) +// But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! +// - Only ok at 600MHz else some disturbances visible + + + +#define TOP_BORDER 40 +#define PIN_HBLANK 15 + +#define PIN_R_B2 33 +#define PIN_R_B1 4 +#define PIN_R_B0 3 +#define PIN_G_B2 2 +#define PIN_G_B1 13 +#define PIN_G_B0 11 +#define PIN_B_B1 12 +#define PIN_B_B0 10 + + +#define DMA_HACK 0x80 + +#define R16(rgb) ((rgb>>8)&0xf8) +#define G16(rgb) ((rgb>>3)&0xfc) +#define B16(rgb) ((rgb<<3)&0xf8) + +// VGA 640x480@60Hz +// Screen refresh rate 60 Hz +// Vertical refresh 31.46875 kHz +// Pixel freq. 25.175 MHz +// +// Visible area 640 25.422045680238 us +// Front porch 16 0.63555114200596 us +// Sync pulse 96 3.8133068520357 us +// Back porch 48 1.9066534260179 us +// Whole line 800 31.777557100298 us + +#define frame_freq 60.0 // Hz +#define line_freq 31.46875 // KHz +#define pix_freq (line_freq*800) // KHz (25.175 MHz) + +// pix_period = 39.7ns +// H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) +#define frontporch_pix 20 //16 +#define backporch_pix 44 //48 + +// Flexio Clock +// PLL3 SW CLOCK (3) => 480 MHz +// PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) +#define FLEXIO_CLK_SEL_PLL3 3 +#define FLEXIO_CLK_SEL_PLL5 2 + +/* Set video PLL */ +// There are /1, /2, /4, /8, /16 post dividers for the Video PLL. +// The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, +// and CCM_ANALOG_MISC2 register sets according to the following equation. +// PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + +// nfact: +// This field controls the PLL loop divider. +// Valid range for DIV_SELECT divider value: 27~54. + +#define POST_DIV_SELECT 2 + +// Full buffer including back/front porch +static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; +static uint32_t dstbuffer __attribute__((aligned(32))); + +// Visible vuffer +static vga_pixel * vga_buffer; +static int vga_width; +static int vga_height; +static int vga_stride; + +static int maxpixperline; +static int left_border; +static int right_border; +static int line_double; +static int pix_shift; +static int ref_div_select; +static int ref_freq_num; +static int ref_freq_denom; +static int ref_pix_shift; +static int combine_shiftreg; + +#ifdef DEBUG +static uint32_t ISRTicks_prev = 0; +volatile uint32_t ISRTicks = 0; +#endif + +uint8_t T4_DSP::_rst; +uint8_t T4_DSP::_cs; +uint8_t T4_DSP::_dc; +uint8_t T4_DSP::_mosi; +uint8_t T4_DSP::_sclk; +uint8_t T4_DSP::_vsync_pin = -1; +DMAChannel T4_DSP::flexio1DMA; +DMAChannel T4_DSP::flexio2DMA; + +static volatile uint32_t VSYNC = 0; +static volatile uint32_t currentLine=0; +#define NOP asm volatile("nop\n\t"); +static gfx_mode_t gfxmode = MODE_UNDEFINED; + + +FASTRUN void T4_DSP::TFT_isr(void) { + dmatx.clearInterrupt(); + curTransfer++; + if (curTransfer >= nbTransfer) { + curTransfer = 0; + if (cancelled) { + dmatx.disable(); + rstop = 1; + } + } + arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); +} + +FASTRUN void T4_DSP::QT3_isr(void) { + TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); + TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); + + cli(); + + // V-PULSE + if (currentLine > 0) { + digitalWrite(_vsync_pin, 1); + VSYNC = 0; + } else { + digitalWrite(_vsync_pin, 0); + VSYNC = 1; + } + + currentLine++; + currentLine = currentLine % 525; + + + uint32_t y = (currentLine - TOP_BORDER) >> line_double; + // Visible area + + if (y >= 0 && y < vga_height) { + // Disable DMAs + //DMA_CERQ = flexio2DMA.channel; + //DMA_CERQ = flexio1DMA.channel; + + // Setup source adress + // Aligned 32 bits copy + unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; + flexio2DMA.TCD->SADDR = p; + if (pix_shift & DMA_HACK) + { + // Unaligned copy + uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; + flexio1DMA.TCD->SADDR = p2; + } + else { + p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 + flexio1DMA.TCD->SADDR = p; + } + + // Enable DMAs + //flexio2DMA.enable(); + //flexio1DMA.enable(); + DMA_SERQ = flexio2DMA.channel; + DMA_SERQ = flexio1DMA.channel; + arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); + } + sei(); + +#ifdef DEBUG + ISRTicks++; +#endif + asm volatile("dsb"); +} + +static void setDmaStruct() { + uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; + uint16_t * fb = (uint16_t*)malloc(remaining); + tft_buffer = fb; + tft_width = TFT_WIDTH; + tft_height = TFT_HEIGHT; + tft_stride = TFT_WIDTH; + uint16_t col=RGBVAL16(0x00,0x00,0x00); + int i=0; + while (remaining > 0) { + int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); + blocks[i] = fb; + for (int j=0;jATTR_DST = 1; + dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); + dmasettings[i].interruptAtCompletion(); + fb += len/2; + remaining -= len; + i++; + } + dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); + nbTransfer = i; +} + +static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 +{ +//if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; + CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE + | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 + | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); + CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; + CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock + const int div_post_pll = 1; // other values: 2,4 + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass +} + +T4_DSP::T4_DSP() +{ + _cs = TFT_CS; + _dc = TFT_DC; + _rst = TFT_RST; + _mosi = TFT_MOSI; + _sclk = TFT_SCLK; + pinMode(_dc, OUTPUT); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, 1); + digitalWrite(_dc, 1); + _vsync_pin = 8; +} + + +void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { + int dx=0; + int dy=0; + digitalWrite(_dc, 0); + SPI.transfer(TFT_CASET); + digitalWrite(_dc, 1); + SPI.transfer16(x1+dx); + digitalWrite(_dc, 1); + SPI.transfer16(x2+dx); + digitalWrite(_dc, 0); + SPI.transfer(TFT_PASET); + digitalWrite(_dc, 1); + SPI.transfer16(y1+dy); + digitalWrite(_dc, 1); + SPI.transfer16(y2+dy); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + return; +} + +void T4_DSP::tft_setup(bool isST) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + // RESET if reset pin defined + if (_rst != 0xff) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + const uint8_t *addr = init_commands; + uint8_t count; + digitalWrite(_cs, 0); + while (count = *addr++) { + uint8_t command = *addr++; + if ( (command == TFT_INVON) && (!isST) ) { + // Skip TFT_INVON for ILI + } + else { + digitalWrite(_dc, 0); // command + SPI.transfer(command); + uint16_t ms = count & DELAY_MASK; + count &= ~DELAY_MASK; + while (--count > 0) { // data + uint8_t data = *addr++; + if ( (command == TFT_MADCTL) && (isST) ) { + data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; + } + digitalWrite(_dc, 1); + SPI.transfer(data); + } + if (ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + digitalWrite(_cs, 1); + SPI.endTransaction(); + delay(2); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + } + } + } + digitalWrite(_cs, 1); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + SPI.endTransaction(); + /* + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_dc, 0); + digitalWrite(_cs, 0); + SPI.transfer(TFT_MADCTL); + digitalWrite(_dc, 1); + SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); + // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); + digitalWrite(_cs, 1); + SPI.endTransaction(); + */ + cancelled = false; +} + +// display VGA image +gfx_error_t T4_DSP::begin(gfx_mode_t mode) +{ + uint32_t flexio_clock_div; + combine_shiftreg = 0; +// int div_select = 49; +// int num = 135; +// int denom = 100; + int div_select = 20; + int num = 9800; + int denom = 10000; + int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; + int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; + set_videoClock(div_select,num,denom,true); + +#ifdef DEBUG + Serial.println(mode); + Serial.println("mode"); +#endif + + switch(mode) + { + case MODE_TFTILI_320x240: +#ifdef DEBUG + Serial.println("TFTILI_320x240"); +#endif + tft_setup(false); + gfxmode = mode; + break; + case MODE_TFTST_320x240: +#ifdef DEBUG + Serial.println("TFTST_320x240"); +#endif + tft_setup(true); + gfxmode = mode; + break; + + case MODE_VGA_320x240: +#ifdef DEBUG + Serial.println("VGA_320x240"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_320x480: +#ifdef DEBUG + Serial.println("VGA_320x480"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_640x240: +#ifdef DEBUG + Serial.println("VGA_640x240"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/pix_freq; + line_double = 1; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_640x480: +#ifdef DEBUG + Serial.println("VGA_640x480"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = (flexio_freq/pix_freq); + line_double = 0; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_512x240: +#ifdef DEBUG + Serial.println("VGA_512x240"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 1; + pix_shift = 0; + break; + + case MODE_VGA_512x480: +#ifdef DEBUG + Serial.println("VGA_512x480"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 0; + pix_shift = 0; + break; + + case MODE_VGA_352x240: +#ifdef DEBUG + Serial.println("VGA_352x240"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_352x480: +#ifdef DEBUG + Serial.println("VGA_352x480"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + } + + if (mode >= MODE_VGA_320x240) + { + if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { + fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); + digitalWrite(_cs, 0); + digitalWrite(_dc, 0); + SPI.transfer(TFT_DISPOFF); + digitalWrite(_cs, 1); + delay(20); + digitalWrite(_cs, 0); + digitalWrite(_cs, 1); + } + gfxmode = mode; + + maxpixperline = vga_stride; + // Save param for tweek adjustment + ref_div_select = div_select; + ref_freq_num = num; + ref_freq_denom = denom; + ref_pix_shift = pix_shift; + +#ifdef DEBUG + Serial.println("frequency"); + Serial.println(flexio_freq); + Serial.println("div"); + Serial.println(flexio_freq/pix_freq); +#endif + + pinMode(_vsync_pin, OUTPUT); + pinMode(PIN_HBLANK, OUTPUT); + + /* Basic pin setup FlexIO1 */ + pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 + pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 + pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 + pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 + /* Basic pin setup FlexIO2 */ + pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 + pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 + pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 + pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 + + /* High speed and drive strength configuration */ + *(portControlRegister(PIN_G_B2)) = 0xFF; + *(portControlRegister(PIN_R_B0)) = 0xFF; + *(portControlRegister(PIN_R_B1)) = 0xFF; + *(portControlRegister(PIN_R_B2)) = 0xFF; + *(portControlRegister(PIN_B_B0)) = 0xFF; + *(portControlRegister(PIN_B_B1)) = 0xFF; + *(portControlRegister(PIN_G_B0)) = 0xFF; + *(portControlRegister(PIN_G_B1)) = 0xFF; + + /* Set clock for FlexIO1 and FlexIO2 */ + CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) + | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); + CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) + | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); + + + /* Set up pin mux FlexIO1 */ + *(portConfigRegister(PIN_G_B2)) = 0x14; + *(portConfigRegister(PIN_R_B0)) = 0x14; + *(portConfigRegister(PIN_R_B1)) = 0x14; + *(portConfigRegister(PIN_R_B2)) = 0x14; + /* Set up pin mux FlexIO2 */ + *(portConfigRegister(PIN_B_B0)) = 0x14; + *(portConfigRegister(PIN_B_B1)) = 0x14; + *(portConfigRegister(PIN_G_B0)) = 0x14; + *(portConfigRegister(PIN_G_B1)) = 0x14; + + /* Enable the clock */ + CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + /* Enable the FlexIO with fast access */ + FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + + uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; + uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; + + /* Shifter 0 registers for FlexIO2 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 + inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter + stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled + startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable + timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 + timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock + pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output + pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity + shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode + /* Shifter 0 registers for FlexIO1 */ + FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + /* Shifter 0 registers for FlexIO1 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 + FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + if (combine_shiftreg) { + pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled + FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + } + /* Timer 0 registers for FlexIO2 */ + timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset + timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output + timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset + timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare + timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert + stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled + startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled + if (combine_shiftreg) { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag + } + else { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag + } + triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low + triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected + pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled + //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 + //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high + timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode + // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) + + int shifts_per_transfer; + if (combine_shiftreg) { + shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 + } + else { + shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 + } + FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); + /* Timer 0 registers for FlexIO1 */ + FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); +#ifdef DEBUG + Serial.println("FlexIO setup complete"); +#endif + + /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ + if (combine_shiftreg) { + FLEXIO2_SHIFTSDEN |= (1<<1); + FLEXIO1_SHIFTSDEN |= (1<<1); + } + else { + FLEXIO2_SHIFTSDEN |= (1<<0); + FLEXIO1_SHIFTSDEN |= (1<<0); + } + /* Disable DMA channel so it doesn't start transferring yet */ + flexio1DMA.disable(); + flexio2DMA.disable(); + /* Set up DMA channel to use Shifter 0 trigger */ + flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); + flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); + + + if (combine_shiftreg) { + flexio2DMA.TCD->NBYTES = 8; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 8; + flexio2DMA.TCD->CITER = maxpixperline / 8; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + flexio1DMA.TCD->NBYTES = 8; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 8; + flexio1DMA.TCD->CITER = maxpixperline / 8; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Setup DMA2 Flexio2 copy + flexio2DMA.TCD->NBYTES = 4; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 4; + flexio2DMA.TCD->CITER = maxpixperline / 4; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + // Setup DMA1 Flexio1 copy + // Use pixel shift to avoid color smearing? + if (pix_shift & DMA_HACK) + { + if (pix_shift & 0x3 == 0) { + // Aligned 32 bits copy (32bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Unaligned (source) 32 bits copy (8bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 1; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion + } + } + else + { + // Aligned 32 bits copy + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + } + +#ifdef DEBUG + Serial.println("DMA setup complete"); +#endif + + // enable clocks for QTIMER3: generates the 15KHz for hsync + // Pulse: + // low : 3.8133 us => 569x6.7ns + // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) + // (OLD TEST) + // (4us low, 28us high => 32us) + // (597x6.7ns for 4us) + // (4179x6.7ns for 28us) + CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 + //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 + + #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz + #define MARGIN_D 1000 + + TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer + // Invert output pin as we want the interupt on rising edge + TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) + TMR3_CNTR3 = 0; + TMR3_LOAD3 = 0; + + /* Inverted timings */ + unsigned long long cpu_freq = F_CPU; + unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; + int rate2 = rate; + + int substract = 1; + if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { + substract=5; + rate2=1652; + } + + #ifdef DEBUG + Serial.print("MARGIN_N is: "); + Serial.println(rate2, DEC); + Serial.print("SUBSTRACT is: "); + Serial.println(substract, DEC); +#endif + TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; + TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; + /* + TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; + */ + TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on + TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), + // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) + //configure Teensy pin Compare output + IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 + attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function + NVIC_ENABLE_IRQ(IRQ_QTIMER3); +#ifdef DEBUG + Serial.println("QTIMER3 setup complete"); + Serial.print("V-PIN is "); + Serial.println(_vsync_pin); +#endif + + /* initialize gfx buffer */ + if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift + if (gfxbuffer == NULL) return(GFX_ERROR); +#ifdef DEBUG + Serial.println("Memory allocated"); +#endif + + memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); + vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; +#ifdef DEBUG + Serial.println(vga_stride); + Serial.println(vga_height); + Serial.println("Screen cleared"); +#endif + } + + return(GFX_OK); +} + +gfx_mode_t T4_DSP::getMode(void) +{ + return gfxmode; +} + +void T4_DSP::startRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + curTransfer = 0; + rstop = 0; + //dmatx.begin(true); + dmatx.attachInterrupt(TFT_isr); + setDmaStruct(); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + + digitalWrite(_cs, HIGH); + SPI.begin(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + + LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: + LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX + LPSPIP_TCR = 15; // Framesize 16 Bits + //LPSPIP_FCR = 0; // Fifo Watermark + LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable + LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: + dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); + + dmatx = dmasettings[0]; + digitalWrite(_cs, 0); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + dmatx.enable(); + } +} + + +void T4_DSP::stopRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + rstop = 1; + unsigned long m = millis(); + cancelled = true; + while (!rstop) { + if ((millis() - m) > 100) break; + delay(10); + asm volatile("wfi"); + }; + rstop = 0; + delay(50); + cancelled = false; + dmatx.detachInterrupt(); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + SPI.end(); +#ifdef ST7789 +// begin(gfxmode); +#endif + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + } +} + +int T4_DSP::get_frame_buffer_size(int *width, int *height) { + if (gfxmode < MODE_VGA_320x240) { + if (width != nullptr) *width = tft_width; + if (height != nullptr) *height = tft_height; + return tft_stride; + } + else { + if (width != nullptr) *width = vga_width; + if (height != nullptr) *height = vga_height; + return vga_stride; + } +} + +void T4_DSP::waitSync() +{ + if (gfxmode >= MODE_VGA_320x240) { + while (VSYNC == 0) {}; + } +} + +void T4_DSP::waitLine(int line) +{ + if (gfxmode >= MODE_VGA_320x240) { + while (currentLine != line) {}; + } +} + +/*********************************************************************************************** + No DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreenNoDma(uint16_t color) { + if (gfxmode < MODE_VGA_320x240) { + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + int i,j; + for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(arx, ary, arx+arw-1, ary+arh-1); + bitmap = bitmap + bmp_offy*w + bmp_offx; + for (int row=0;row> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + bits = *charpt++; + //digitalWrite(_dc, 1); + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + x +=8; + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + else { + drawText(x, y, text, fgcolor, bgcolor, doublesize); + } +} + + +/*********************************************************************************************** + DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreen(uint16_t color) { + int i,j; + if (gfxmode < MODE_VGA_320x240) { + for (j=0; j> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + dst=&tft_buffer[l*tft_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + x +=8; + } + } + else { + vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); + vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); + vga_pixel * dst; + while ((c = *text++)) { + const unsigned char * charpt=&font8x8[c][0]; + int l=y; + for (int i=0;i<8;i++) + { + unsigned char bits; + if (doublesize) { + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + x +=8; + } + } +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { + drawSprite(x,y,bitmap, 0,0,0,0); +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) +{ + int bmp_offx = 0; + int bmp_offy = 0; + uint16_t *bmp_ptr; + int w =*bitmap++; + int h = *bitmap++; + if ( (arw == 0) || (arh == 0) ) { + // no crop window + arx = x; + ary = y; + arw = w; + arh = h; + } + else { + if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + int l=ary; + bitmap = bitmap + bmp_offy*w + bmp_offx; + + if (gfxmode < MODE_VGA_320x240) { + for (int row=0;row tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]; + pos +=step; + } + #endif + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i 2) ) y += (tft_height-height)/2; + uint16_t * dst=&tft_buffer[y*tft_stride]; + if (width > tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]]; + pos +=step; + } +#endif + } + else if ((width*2) == tft_width) { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]]; + *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i tft_width) { + int step = ((width << 8)/tft_width); + int pos = 0; + for (int i=0; i> 8]]; + pos +=step; + } + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = pix; + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i +#include +#endif + +#include "platform_config.h" +#include "iopins.h" + + + +#ifndef TFT_WIDTH +#define TFT_WIDTH 320 +#endif +#define TFT_REALWIDTH 320 + +#ifndef TFT_HEIGHT +#define TFT_HEIGHT 240 +#endif +#define TFT_REALHEIGHT 240 + + +typedef enum gfx_mode_t +{ + MODE_UNDEFINED = 0, + MODE_TFTILI_320x240 = 1, + MODE_TFTST_320x240 = 2, + MODE_VGA_320x240 = 3, + MODE_VGA_320x480 = 4, + MODE_VGA_352x240 = 5, + MODE_VGA_352x480 = 6, + MODE_VGA_512x240 = 7, + MODE_VGA_512x480 = 8, + MODE_VGA_640x240 = 9, + MODE_VGA_640x480 = 10 +} gfx_mode_t; + +typedef enum gfx_error_t +{ + GFX_OK = 0, + GFX_ERROR = -1 +} gfx_error_t; + + +#ifdef __cplusplus + +class T4_DSP +{ + public: + T4_DSP(); + + gfx_error_t begin(gfx_mode_t mode); + gfx_mode_t getMode(void); + void startRefresh(void); + void stopRefresh(); + + int get_frame_buffer_size(int *width, int *height); + void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); + + // wait next Vsync + void waitSync(); + void waitLine(int line); + + // NoDMA functions + void fillScreenNoDma(uint16_t color); + void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + // DMA functions + void fillScreen(uint16_t color); + void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + void writeLine(int width, int height, int y, uint16_t *buf); + void writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + void writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16); + void writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + + protected: + static uint8_t _rst, _cs, _dc; + static uint8_t _mosi, _sclk; + static uint8_t _vsync_pin; + static DMAChannel flexio1DMA; + static DMAChannel flexio2DMA; + void tft_setup(bool isST); + static void TFT_isr(void); + static void QT3_isr(void); +}; + +#endif +#endif diff --git a/MCUME_teensy41/teensynofrendo/teensynofrendo.ino b/MCUME_teensy41/teensynofrendo/teensynofrendo.ino index ca6392b..a0867e4 100644 --- a/MCUME_teensy41/teensynofrendo/teensynofrendo.ino +++ b/MCUME_teensy41/teensynofrendo/teensynofrendo.ino @@ -3,132 +3,21 @@ extern "C" { #include "emuapi.h" } -#include "nes_emu.h" - -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -TFT_T_DMA tft; -#else -#include "tft_t_dma.h" -TFT_T_DMA tft = TFT_T_DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, TFT_TOUCH_CS, TFT_TOUCH_INT); -#endif - -bool vgaMode = false; - -static unsigned char palette8[PALETTE_SIZE]; -static unsigned short palette16[PALETTE_SIZE]; -static IntervalTimer myTimer; -volatile boolean vbl=true; -static int skip=0; -static elapsedMicros tius; - -static void vblCount() { - if (vbl) { - vbl = false; - } else { - vbl = true; - } -} - -void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) -{ - if (index>8, - 320 & 0xFF, // YEND = 320 - ST7735_INVON , DELAY, // 7: hack - 10, - ST7735_NORON , DELAY, // 8: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 9: Main screen turn on, no args, w/delay - 255 -#endif -}; - -static void dmaInterrupt() { - dmatx.clearInterrupt(); - curTransfer++; - if (curTransfer >= nbTransfer) { - curTransfer = 0; - if (cancelled) { - dmatx.disable(); - rstop = 1; - } - } - arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2); -} - -static void setDmaStruct() { - uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; - int i=0; - uint16_t col=RGBVAL16(0x00,0x00,0x00);; - while (remaining > 0) { - uint16_t * fb = blocks[i]; - int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining); -#ifdef TFT_DEBUG - Serial.println((unsigned long)blocks[i]); - Serial.println(remaining); -#endif - switch (i) { - case 0: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb0[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0x00); -#endif - break; - case 1: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb1[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0xff); -#endif - break; - case 2: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb2[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0x00,0xff); -#endif - break; - case 3: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb3[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0xff,0x00,0xff); -#endif - break; - } - blocks[i] = fb; - if (blocks[i] == 0) { - Serial.print("ILI9341 allocaltion failed for block "); - Serial.println(i); - delay(10000); - } - - for (int j=0;jATTR_DST = 1; - dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); - dmasettings[i].interruptAtCompletion(); - remaining -= len; - i++; - } - dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); - nbTransfer = i; -#ifdef TFT_DEBUG - Serial.println(nbTransfer); -#endif -} - - -TFT_T_DMA::TFT_T_DMA(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso, uint8_t touch_cs, uint8_t touch_irq) -{ - _cs = cs; - _dc = dc; - _rst = rst; - _mosi = mosi; - _sclk = sclk; - _miso = miso; - pinMode(_dc, OUTPUT); - pinMode(_cs, OUTPUT); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); - if ( (touch_cs != 255) && (touch_irq != 255) ) { - _touch_irq = touch_irq; - _touch_cs = touch_cs; - pinMode(_touch_cs, OUTPUT); - pinMode(touch_irq, INPUT_PULLUP); - digitalWrite(_touch_cs, 1); - } -} - - -void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { - int dx=0; - int dy=0; -#ifdef ST7789 - if (TFT_REALWIDTH == TFT_REALHEIGHT) - { -#ifdef ROTATE_SCREEN - if (!flipped) { - dy += 80; - } -#else - if (flipped) { - dx += 80; - } -#endif - } -#endif - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - SPI.transfer16(x1+dx); - digitalWrite(_dc, 1); - SPI.transfer16(x2+dx); - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - digitalWrite(_dc, 1); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - return; - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - - SPI.transfer16(x1+dx); - SPI.transfer16(x2+dx); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - -void TFT_T_DMA::begin(void) { - SPI.setMOSI(_mosi); - SPI.setMISO(_miso); - SPI.setSCK(_sclk); - SPI.begin(); - - // Initialize display - if (_rst != 0xff) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - const uint8_t *addr = init_commands; - digitalWrite(_cs, 0); -#ifdef ILI9341 - while (1) { - uint8_t count = *addr++; - if (count-- == 0) break; - - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - - while (count-- > 0) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - } - - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(ILI9341_DISPON); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); -#endif -#ifdef ST7789 - uint8_t numCommands, numArgs; - uint16_t ms; - numCommands = *addr++; // Number of commands to follow - while(numCommands--) { // For each command... - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - numArgs = *addr++; // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs > 1) { // For each argument... - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - numArgs--; - } - - if (numArgs) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - if(ms) { - ms = *addr++; // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - digitalWrite(_cs, 1); - SPI.endTransaction(); - delay(ms); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - } - } - digitalWrite(_cs, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - SPI.endTransaction(); - - cancelled = false; - -#ifdef FLIP_SCREEN - flipscreen(true); -#else - flipscreen(false); -#endif -#ifdef ST7789 - if (TFT_REALWIDTH != TFT_REALHEIGHT) - { - flipscreen(true); - } -#endif -}; - - - -void TFT_T_DMA::flipscreen(bool flip) -{ - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(TFT_MADCTL); - digitalWrite(_dc, 1); - if (flip) { - flipped=true; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB); -#endif -#endif - } - else { - flipped=false; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB); -#endif -#endif - } - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - -boolean TFT_T_DMA::isflipped(void) -{ - return(flipped); -} - - -#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) - - -void TFT_T_DMA::startDMA(void) { - curTransfer = 0; - rstop = 0; - //dmatx.begin(true); - dmatx.attachInterrupt(dmaInterrupt); - setDmaStruct(); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - - digitalWrite(_cs, HIGH); - SPI.begin(); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); - - - LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: - LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX - LPSPIP_TCR = 15; // Framesize 16 Bits - //LPSPIP_FCR = 0; // Fifo Watermark - LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable - LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: - dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); - - dmatx = dmasettings[0]; - digitalWrite(_cs, 0); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - dmatx.enable(); -} - - -void TFT_T_DMA::stopDMA(void) { - rstop = 0; - wait(); - delay(50); - cancelled = false; - dmatx.detachInterrupt(); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - SPI.end(); -#ifdef ST7789 - begin(); -#endif -#ifdef ILI9341 - SPI.begin(); - digitalWrite(_cs, 0); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - SPI.endTransaction(); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); -} - -void TFT_T_DMA::wait(void) { - rstop = 1; - unsigned long m = millis(); - cancelled = true; - while (!rstop) { - if ((millis() - m) > 100) break; - delay(10); - asm volatile("wfi"); - }; - rstop = 0; -} - -int TFT_T_DMA::get_frame_buffer_size(int *width, int *height){ - if (width != nullptr) *width = TFT_REALWIDTH; - if (height != nullptr) *height = TFT_REALHEIGHT; - return TFT_REALWIDTH; -} - - -/*********************************************************************************************** - Touch functions - ***********************************************************************************************/ -/* Code based on ... - * - * @file XPT2046.cpp - * @date 19.02.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the XPT2046 driver for Arduino. - */ - -#define ADC_MAX 0x0fff - -void TFT_T_DMA::enableTouchIrq() -{ - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 }; - SPI.transfer((void*)&buf[0],3); - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); -} - -//Default callibration for non flipped -#define TX_MIN 30 -#define TY_MIN 20 -#define TX_MAX 300 -#define TY_MAX 220 - -//Default callibration for flipped -#define TFX_MIN 20 -#define TFY_MIN 25 -#define TFX_MAX 288 -#define TFY_MAX 221 - -static uint16_t txMin; -static uint16_t tyMin; -static uint16_t txMax; -static uint16_t tyMax; - - -void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { - if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) { - txMin = xMin; - tyMin = yMin; - txMax = xMax; - tyMax = yMax; - } - else { - if (flipped) { - txMin = TFX_MIN; - tyMin = TFY_MIN; - txMax = TFX_MAX; - tyMax = TFY_MAX; - } - else { - txMin = TX_MIN; - tyMin = TY_MIN; - txMax = TX_MAX; - tyMax = TY_MAX; - } - } -} - - -void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - if ( TOUCH_ENABLED() ) { - uint16_t x = 0; - uint16_t y = 0; - uint16_t z1 = 0; - uint16_t z2 = 0; - uint8_t i = 0; - int16_t xraw=0, yraw=0; - - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - - for(; i < 15; i++) { - // SPI requirer 32bit aliment - uint8_t buf[12] = { - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00 - }; - SPI.transfer(&buf[0], &buf[0], 12); - y += (buf[1] << 8 | buf[2])>>3; - x += (buf[4] << 8 | buf[5])>>3; - z1 += (buf[7] << 8 | buf[8])>>3; - z2 += (buf[10] << 8 | buf[11])>>3; - } - enableTouchIrq(); - - if(i == 0) { - *oX = 0; - *oY = 0; - *oZ = 0; - } - else { - x /= i; - y /= i; - z1 /= i; - z2 /= i; - } - - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); - int z = z1 + ADC_MAX - z2; - if (flipped) { - xraw = x; - yraw = y; - } else { - xraw = ADC_MAX - x; - yraw = ADC_MAX - y; - } - xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1); - yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1); - - *oX = xraw; - *oY = yraw; - *oZ = z; - } - else - { - *oX = 0; - *oY = 0; - *oZ = 0; - } -} - -void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - readRaw(oX,oY,oZ); - // callibrate ... - if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin); - if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin); - //Serial.print(*oX); - //Serial.print(" "); - //Serial.println(*oY); -} - - -/*********************************************************************************************** - No DMA functions - ***********************************************************************************************/ -void TFT_T_DMA::fillScreenNoDma(uint16_t color) { - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - int i,j; - for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(arx, ary, arx+arw-1, ary+arh-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - bits = *charpt++; - //digitalWrite(_dc, 1); - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - x +=8; -#ifdef ILI9341 - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); -#endif - digitalWrite(_cs, 1); - SPI.endTransaction(); - } - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - - - -/*********************************************************************************************** - DMA functions - ***********************************************************************************************/ -uint16_t * TFT_T_DMA::getLineBuffer(int j) -{ - uint16_t * block=blocks[j>>6]; - return(&block[(j&0x3F)*TFT_REALWIDTH]); -} - -void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) { - uint8_t *buffer=buf; - uint8_t *src; - - int i,j,y=0; - if (width*2 <= TFT_REALWIDTH) { - for (j=0; j>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH]; - for (i=0; i>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x]; - for (i=0; i>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - block=blocks[l>>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt++; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - x +=8; - } -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { - drawSprite(x,y,bitmap, 0,0,0,0); -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) -{ - int bmp_offx = 0; - int bmp_offy = 0; - uint16_t *bmp_ptr; - - int w =*bitmap++; - int h = *bitmap++; - - - if ( (arw == 0) || (arh == 0) ) { - // no crop window - arx = x; - ary = y; - arw = w; - arh = h; - } - else { - if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - int l=ary; - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx]; - bmp_ptr = (uint16_t*)bitmap; - for (int col=0;col -#include -#include -#endif - -#include "tft_t_dma_config.h" - -#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) -#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define R16(rgb) ((rgb>>8)&0xf8) -#define G16(rgb) ((rgb>>3)&0xfc) -#define B16(rgb) ((rgb<<3)&0xf8) - -#define PAL_COLOR_MASK 0xff - -#ifdef LOHRES -#define TFT_WIDTH 240 -#define TFT_REALWIDTH 240 -#else -#define TFT_WIDTH 256 -#define TFT_REALWIDTH 320 -#endif -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - -//#define WIDTH 272 -//#define HEIGHT 228 - -#define LINES_PER_BLOCK 64 -#define NR_OF_BLOCK 4 -#define SCREEN_DMA_NUM_SETTINGS NR_OF_BLOCK - - -#ifdef ILI9341 - -#define ILI9341_NOP 0x00 -#define ILI9341_SWRESET 0x01 -#define ILI9341_RDDID 0x04 -#define ILI9341_RDDST 0x09 - -#define ILI9341_SLPIN 0x10 -#define ILI9341_SLPOUT 0x11 -#define ILI9341_PTLON 0x12 -#define ILI9341_NORON 0x13 - -#define ILI9341_RDMODE 0x0A -#define ILI9341_RDMADCTL 0x0B -#define ILI9341_RDPIXFMT 0x0C -#define ILI9341_RDIMGFMT 0x0D -#define ILI9341_RDSELFDIAG 0x0F - -#define ILI9341_INVOFF 0x20 -#define ILI9341_INVON 0x21 -#define ILI9341_GAMMASET 0x26 -#define ILI9341_DISPOFF 0x28 -#define ILI9341_DISPON 0x29 - -#define ILI9341_CASET 0x2A -#define ILI9341_PASET 0x2B -#define ILI9341_RAMWR 0x2C -#define ILI9341_RAMRD 0x2E - -#define ILI9341_PTLAR 0x30 -#define ILI9341_MADCTL 0x36 -#define ILI9341_VSCRSADD 0x37 -#define ILI9341_PIXFMT 0x3A - -#define ILI9341_FRMCTR1 0xB1 -#define ILI9341_FRMCTR2 0xB2 -#define ILI9341_FRMCTR3 0xB3 -#define ILI9341_INVCTR 0xB4 -#define ILI9341_DFUNCTR 0xB6 - -#define ILI9341_PWCTR1 0xC0 -#define ILI9341_PWCTR2 0xC1 -#define ILI9341_PWCTR3 0xC2 -#define ILI9341_PWCTR4 0xC3 -#define ILI9341_PWCTR5 0xC4 -#define ILI9341_VMCTR1 0xC5 -#define ILI9341_VMCTR2 0xC7 - -#define ILI9341_RDID1 0xDA -#define ILI9341_RDID2 0xDB -#define ILI9341_RDID3 0xDC -#define ILI9341_RDID4 0xDD - -#define ILI9341_GMCTRP1 0xE0 -#define ILI9341_GMCTRN1 0xE1 - -#define ILI9341_MADCTL_MY 0x80 -#define ILI9341_MADCTL_MX 0x40 -#define ILI9341_MADCTL_MV 0x20 -#define ILI9341_MADCTL_ML 0x10 -#define ILI9341_MADCTL_RGB 0x00 -#define ILI9341_MADCTL_BGR 0x08 -#define ILI9341_MADCTL_MH 0x04 - -#define TFT_CASET ILI9341_CASET -#define TFT_PASET ILI9341_PASET -#define TFT_RAMWR ILI9341_RAMWR -#define TFT_MADCTL ILI9341_MADCTL - -#endif - - -#ifdef ST7789 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_RGB 0x00 -#define ST77XX_MADCTL_BGR 0x08 -#define ST77XX_MADCTL_MH 0x04 - -#define TFT_CASET ST7735_CASET -#define TFT_PASET ST7735_RASET -#define TFT_RAMWR ST7735_RAMWR -#define TFT_MADCTL ST7735_MADCTL - -#endif - - - -#ifdef __cplusplus - -class TFT_T_DMA -{ - public: - TFT_T_DMA(uint8_t _CS, uint8_t _DC, uint8_t _RST = 255, uint8_t _MOSI=11, uint8_t _SCLK=13, uint8_t _MISO=12, uint8_t touch_cs=38, uint8_t touch_irq=37); - - void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); - void begin(void); - void flipscreen(bool flip); - boolean isflipped(void); - void startDMA(void); - void stopDMA(); - int get_frame_buffer_size(int *width, int *height); - - // Touch screen functions - #define TOUCH_ENABLED() ((_touch_cs != 255) && (_touch_irq != 255)) - bool isTouching(void) { return ((!TOUCH_ENABLED())?false:(digitalRead(_touch_irq) == LOW)); } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax); - - // NoDMA functions - void writeScreenNoDma(const uint16_t *pcolors); - void fillScreenNoDma(uint16_t color); - void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - // DMA functions - uint16_t * getLineBuffer(int j); - void writeScreen(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int y, uint16_t *buf); - void fillScreen(uint16_t color); - void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - protected: - uint8_t _rst, _cs, _dc; - uint8_t _miso, _mosi, _sclk; - uint8_t _touch_irq=255, _touch_cs=255; - bool flipped=false; - - void wait(void); - void enableTouchIrq(); -}; - -#endif -#endif diff --git a/MCUME_teensy41/teensynofrendo/tft_t_dma_config.h b/MCUME_teensy41/teensynofrendo/tft_t_dma_config.h deleted file mode 100644 index 354cf74..0000000 --- a/MCUME_teensy41/teensynofrendo/tft_t_dma_config.h +++ /dev/null @@ -1,14 +0,0 @@ -#include "platform_config.h" - -//#define ST7789 1 -//#define ILI9341 1 - -#define TFT_LINEARINT 1 -#define LINEARINT_HACK 1 - -//#define FLIP_SCREEN 1 -//#define TFT_DEBUG 1 -#if defined(__IMXRT1052__) || defined(__IMXRT1062__) -//#define TFT_STATICFB 1 -#endif - diff --git a/MCUME_teensy41/teensynofrendo/vga_t_dma.h b/MCUME_teensy41/teensynofrendo/vga_t_dma.h deleted file mode 100644 index 81a986b..0000000 --- a/MCUME_teensy41/teensynofrendo/vga_t_dma.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - Wrapping class to extend VGA_T4 to TFT_T_DMA -*/ - -#ifndef _VGA_T_DMAH_ -#define _VGA_T_DMAH_ - -#ifdef __cplusplus -#include -#endif - - -#define RGBVAL16(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) - - - - -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 - -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - - - -#ifdef __cplusplus - -class TFT_T_DMA: public VGA_T4 -{ - public: - // Fake touch screen functions - bool isTouching(void) { return false; } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { } - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { }; - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { } - - // fake DMA functions - void startDMA(void) { }; - void stopDMA(void) { }; - - // fake no DMA functions - void writeScreenNoDma(const vga_pixel *pcolors) { writeScreen(pcolors); } - void fillScreenNoDma(vga_pixel color) { clear(color); } - void drawTextNoDma(int16_t x, int16_t y, const char * text, vga_pixel fgcolor, vga_pixel bgcolor, bool doublesize) { drawText(x,y,text,fgcolor,bgcolor,doublesize); } - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, vga_pixel color) { drawRect(x, y, w, h, color); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap) { drawSprite(x, y, bitmap); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh) { drawSprite(x, y, bitmap, croparx, cropary, croparw, croparh); } -}; - - -#endif -#endif diff --git a/MCUME_teensy41/teensynofrendo/nes_emu.cpp b/MCUME_teensy41/teensynofrendo/wrapemu.cpp similarity index 93% rename from MCUME_teensy41/teensynofrendo/nes_emu.cpp rename to MCUME_teensy41/teensynofrendo/wrapemu.cpp index 63c06ca..38331fb 100644 --- a/MCUME_teensy41/teensynofrendo/nes_emu.cpp +++ b/MCUME_teensy41/teensynofrendo/wrapemu.cpp @@ -63,7 +63,8 @@ void nes_Start(char * filename) { strcpy(romname,filename); int romsize = emu_FileSize(filename); - romdata = (char*)emu_Malloc(romsize); + //romdata = (char*)emu_SMalloc(romsize); + romdata = (char*)emu_Malloc(romsize); if (romdata) { int f=emu_FileOpen(filename,"r+b"); @@ -165,15 +166,15 @@ void osd_getinput(void) b &= ~0x0001; if ( (j & MASK_KEY_USER1) || (hk == 'w') ) // START b &= ~0x0008; - if (j & MASK_JOY2_UP) + if ( (j & MASK_JOY2_UP) || (j & MASK_JOY1_UP) ) b &= ~0x0010; - if (j & MASK_JOY2_LEFT) + if ( (j & MASK_JOY2_RIGHT) || (j & MASK_JOY1_RIGHT) ) b &= ~0x0020; - if (j & MASK_JOY2_DOWN) + if ( (j & MASK_JOY2_DOWN) || (j & MASK_JOY1_DOWN) ) b &= ~0x0040; - if (j & MASK_JOY2_RIGHT) + if ( (j & MASK_JOY2_LEFT) || (j & MASK_JOY1_LEFT) ) b &= ~0x0080; - if (j & MASK_JOY2_BTN) // B + if ( (j & MASK_JOY2_BTN) || (j & MASK_JOY1_BTN) ) // B b &= ~0x4000; diff --git a/MCUME_teensy41/teensynofrendo/nes_emu.h b/MCUME_teensy41/teensynofrendo/wrapemu.h similarity index 63% rename from MCUME_teensy41/teensynofrendo/nes_emu.h rename to MCUME_teensy41/teensynofrendo/wrapemu.h index 72ab0f7..d2edbd4 100644 --- a/MCUME_teensy41/teensynofrendo/nes_emu.h +++ b/MCUME_teensy41/teensynofrendo/wrapemu.h @@ -1,4 +1,10 @@ +#ifdef __cplusplus +extern "C" { +#endif extern void nes_Init(void); extern void nes_Step(void); extern void nes_Start(char * filename); extern void nes_Input(int key); +#ifdef __cplusplus +} +#endif diff --git a/MCUME_teensy41/teensyo2em/emuapi.cpp b/MCUME_teensy41/teensyo2em/emuapi.cpp index 0e98162..e128cca 100644 --- a/MCUME_teensy41/teensyo2em/emuapi.cpp +++ b/MCUME_teensy41/teensyo2em/emuapi.cpp @@ -5,25 +5,31 @@ extern "C" { #include "iopins.h" } -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#else -#include "tft_t_dma.h" -#endif +#include -#ifdef HAS_USBKEY +#ifdef HAS_USB #include "USBHost_t36.h" // Read this header first for key info USBHost myusb; USBHub hub1(myusb); +#ifdef HAS_USBKEY KeyboardController keyboard1(myusb); USBHIDParser hid1(myusb); MouseController mouse1(myusb); +#endif +#ifdef HAS_USBMIDI MIDIDevice midi1(myusb); #endif +#ifdef HAS_USBJOY +#define COUNT_JOYSTICKS 4 +JoystickController joysticks[COUNT_JOYSTICKS](myusb); +#endif +#endif static bool emu_writeConfig(void); static bool emu_readConfig(void); static bool emu_eraseConfig(void); +static bool emu_writeGfxConfig(char * display_type); +static int emu_readGfxConfig(void); static bool mouseDetected = false; static bool keyboardDetected = false; @@ -34,6 +40,7 @@ static File file; #define MAX_FILES 64 #define AUTORUN_FILENAME "autorun.txt" +#define GFX_CFG_FILENAME "gfxmode.txt" #define MAX_FILENAME_SIZE 34 #define MAX_MENULINES 9 @@ -53,7 +60,8 @@ static File file; #define MENU_VGA_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) #define MENU_VGA_YOFFSET (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37) -extern TFT_T_DMA tft; +#include "t4_dsp.h" +T4_DSP tft; static int nbFiles=0; static int curFile=0; @@ -65,6 +73,8 @@ static char selected_filename[MAX_FILENAME_SIZE]=""; static char second_selected_filename[MAX_FILENAME_SIZE]=""; static bool menuRedraw=true; static bool autorun=false; +static bool vgahires=false; + static const unsigned short * keys; #ifdef TEECOMPUTER @@ -158,6 +168,29 @@ void emu_Free(void * pt) free(pt); } +#define SMEMPOOL (0x800000) +EXTMEM static unsigned char slowmem[SMEMPOOL]; +static int slowmempt = 0; + +void * emu_SMalloc(unsigned int size) +{ + void * mem = (void*)&slowmem[slowmempt]; + slowmempt += size; + + if ( slowmempt > SMEMPOOL ) { + mem = NULL; + emu_printf("failure to allocate slow"); + } + else { + emu_printf("could allocate slow static "); + emu_printf(size); + } + return mem; +} + +void emu_SFree(void * pt) +{ +} /******************************** * Input and keyboard ********************************/ @@ -329,6 +362,12 @@ int emu_ReadKeys(void) #endif if ( row & 0x02 ) retval |= MASK_JOY2_BTN; + +#ifdef EXTPAD + if ( sh_pressed ) retval |= MASK_KEY_USER3; + if ( fn_pressed ) retval |= MASK_KEY_USER1; + digitalWrite(KLED, 0); +#else // Handle LED flash uint32_t time_ms=millis(); if ((time_ms-last_t_ms) > 100) { @@ -412,8 +451,9 @@ int emu_ReadKeys(void) if ( key_fn ) retval |= MASK_KEY_USER2; if ( ( key_fn ) && (keymatrix[4] == 0x10 )) retval |= MASK_KEY_USER1; +#endif - if ( (key_fn) && (key_sh) ) + if ( (fn_pressed) && (sh_pressed) ) #else if ( ((retval & (MASK_KEY_USER1+MASK_KEY_USER2)) == (MASK_KEY_USER1+MASK_KEY_USER2)) || (retval & MASK_KEY_USER4 ) ) @@ -453,8 +493,10 @@ int emu_ReadKeys(void) while (true) { ; } -#endif +#endif } + + emu_GetJoystick(); return (retval); } @@ -607,7 +649,7 @@ int emu_setKeymap(int index) { } int emu_GetMouse(int *x, int *y, int *buts) { -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBKEY) if (mouse1.available()) { *buts = mouse1.getButtons(); *x = mouse1.getMouseX(); @@ -620,7 +662,23 @@ int emu_GetMouse(int *x, int *y, int *buts) { return 0; } -#ifdef HAS_USBKEY +int emu_GetJoystick(void) { +#if defined(HAS_USB) && (HAS_USBJOY) + for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) { + if (joysticks[joystick_index].available()) { + uint64_t axis_mask = joysticks[joystick_index].axisMask(); + uint64_t axis_changed_mask = joysticks[joystick_index].axisChangedMask(); + uint32_t buttons = joysticks[joystick_index].getButtons(); + Serial.printf("Joystick(%d): buttons = %x", joystick_index, buttons); + Serial.println(); + } + } + return 1; +#endif + return 0; +} + +#if defined(HAS_USB) && (HAS_USBKEY) void OnPress(auto key) { keyboardDetected = true; @@ -764,7 +822,7 @@ int emu_KeyboardDetected(void) { return (keyboardDetected?1:0); } -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) static unsigned char midiBuffer[16]; static unsigned char midiLastCmd=0; static int midiDataCnt=0; @@ -772,8 +830,7 @@ static int midiCmdNbParam=0; #endif void emu_MidiOnDataReceived(unsigned char value) { - -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) //Serial.println(value, HEX); //10000000 = 128 = note off //10010000 = 144 = note on @@ -941,6 +998,7 @@ void emu_MidiOnDataReceived(unsigned char value) { /******************************** * Menu file loader UI ********************************/ +#ifdef FILEBROWSER static int readNbFiles(void) { int totalFiles = 0; @@ -970,8 +1028,6 @@ static int readNbFiles(void) { return totalFiles; } - - void backgroundMenu(void) { menuRedraw=true; tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00)); @@ -981,11 +1037,13 @@ void backgroundMenu(void) { int handleMenu(uint16_t bClick) { if (autorun) { + toggleMenu(false); + menuRedraw=false; return (ACTION_RUN1); } int action = ACTION_NONE; - if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) ) { + if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) || ( bClick & MASK_KEY_USER2 ) ) { char newpath[MAX_FILENAME_PATH]; strcpy(newpath, selection); strcat(newpath, "/"); @@ -996,17 +1054,31 @@ int handleMenu(uint16_t bClick) File file = SD.open(selection); if (file.isDirectory()) { curFile = 0; - nbFiles = readNbFiles(); + nbFiles = readNbFiles(); + menuRedraw=true; } - else { - action = ACTION_RUN1; + else + { #ifdef TEECOMPUTER - if (key_extmode) { + if ( (key_extmode) || ( key_sh) ) { emu_writeConfig(); } + if ( tft.getMode() < MODE_VGA_320x240) { + if ( bClick & MASK_KEY_USER2 ) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + } + //emu_SwapJoysticks(0); #endif + toggleMenu(false); + menuRedraw=false; + return (ACTION_RUN1); } - menuRedraw=true; } else if ( bClick & MASK_KEY_USER1 ) { menuRedraw=true; @@ -1015,19 +1087,14 @@ int handleMenu(uint16_t bClick) strcat(second_selection, "/"); strcat(second_selection, second_selected_filename); action = ACTION_RUN2; - } - else if ( bClick & MASK_KEY_USER2 ) { - menuRedraw=true; - //action = ACTION_RUN3; - emu_SwapJoysticks(0); - } + } else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) { if (curFile!=0) { menuRedraw=true; curFile--; } } - else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { + else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { if ((curFile-9)>=0) { menuRedraw=true; curFile -= 9; @@ -1042,7 +1109,7 @@ int handleMenu(uint16_t bClick) menuRedraw=true; } } - else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { + else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { if ((curFile<(nbFiles-9)) && (nbFiles)) { curFile += 9; menuRedraw=true; @@ -1099,12 +1166,12 @@ int handleMenu(uint16_t bClick) return (action); } -bool menuActive(void) +int menuActive(void) { - return (menuOn); + return (menuOn?1:0); } -void toggleMenu(bool on) { +void toggleMenu(int on) { if (on) { menuOn=true; backgroundMenu(); @@ -1122,7 +1189,7 @@ char * menuSecondSelection(void) { return (second_selection); } - +#endif /******************************** * OSKB handling @@ -1140,8 +1207,9 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) char c[4] = {' ',0,' ',0}; const char * cpt = str; int i=0; - int fb_width,fb_height; - tft.get_frame_buffer_size(&fb_width, &fb_height); + int fb_width,fb_height,fbstride; + + fbstride = tft.get_frame_buffer_size(&fb_width, &fb_height); int ypos = (bottom?(fb_height-2*8):0); int line = row + (bottom?2:0); while ((c[1] = *cpt++)) @@ -1150,7 +1218,7 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0); else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff); if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff); - tft.drawTextNoDma(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); + tft.drawText(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); i++; } } @@ -1248,7 +1316,7 @@ int handleOSKB(void) { return retval; } -void toggleOSKB(bool forceon) { +void toggleOSKB(int forceon) { if (forceon) { oskbOn = true; drawOSKB(); @@ -1332,6 +1400,17 @@ int emu_FileRead(void * buf, int size, int handler) #endif } +int emu_FileWrite(void * buf, int size, int handler) +{ +// emu_printf("emu_FileWrite"); +// emu_printi(handler); +#ifdef HCFH + return (file.write(buf, size)); +#else + return (getFileHandler(handler).write(buf, size)); +#endif +} + int emu_FileGetc(int handler) { // emu_printf("FileGetc"); // emu_printi(handler); @@ -1404,6 +1483,9 @@ unsigned int emu_FileSize(const char * filepath) emu_printf(filesize); lofile.close(); } + else { + emu_printf("filesize failed"); + } return(filesize); } @@ -1489,6 +1571,48 @@ static bool emu_eraseConfig(void) SD.remove (ROMSDIR "/" AUTORUN_FILENAME); } +static bool emu_writeGfxConfig(char * display_type) +{ + bool retval = false; + SD.remove ("/" GFX_CFG_FILENAME); + if (strcmp(display_type, "VGA")) { + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(display_type, strlen(display_type)) != strlen(display_type)) { + emu_printf("GFX config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + } + return retval; +} + +#define CFG_VGA 0 +#define CFG_ILI 1 +#define CFG_ST 2 + +static int emu_readGfxConfig(void) +{ + int retval = CFG_VGA; // No file = VGA + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + if (filesize == 2) // "ST" + { + retval = CFG_ST; + } + else if (filesize == 3) // "ILI" + { + retval = CFG_ILI; + } + lofile.close(); + } + return retval; +} + /******************************** * File IO compatibility ********************************/ @@ -1670,62 +1794,249 @@ FRESULT f_mkdir (const char* path) /******************************** - * Initialization + * GFX wrapper ********************************/ -void emu_init(void) +static unsigned short palette16[PALETTE_SIZE]; +static IntervalTimer myTimer; +volatile boolean vbl=true; +volatile boolean vgatimervsync=false; +static void (*vblCallback)(void) = nullptr; +static int skip=0; + +static void vblCount() { + if (vbl) { + vbl = false; + } else { + vbl = true; + } +} + +void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) +{ + if (index= MODE_VGA_320x240 ) { + if (vgatimervsync) { + while (vbl==vb) {}; + } + else { + tft.waitSync(); + } + } + else { + while (vbl==vb) {}; + } + if (vblCallback != nullptr) { + vblCallback(); + } +} + +void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride) +{ + if (skip == 0) { + tft.writeScreenPal(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); + } +} +void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLinePal(width,height,line, VBuf, palette16); + } +} + +void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine(width,height,line, VBuf); + } +} + +void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine8(width,height,line, VBuf, palette16); + } +} + +int emu_IsVga(void) +{ + return (tft.getMode() >= MODE_VGA_320x240?1:0); +} + +int emu_IsVgaHires(void) +{ + return (tft.getMode() >= MODE_VGA_640x240?1:0); +} + +int emu_FrameSkip(void) +{ + return skip; +} + + +/******************************** + * AUDIO wrapper +********************************/ +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +AudioPlaySystem mymixer; + +void emu_sndInit() { + Serial.println("sound init"); + mymixer.begin_audio(256, mymixer.snd_Mixer); + mymixer.start(); +} + +void emu_sndPlaySound(int chan, int volume, int freq) +{ + if (chan < 6) { + mymixer.sound(chan, freq, volume); + } + /* + Serial.print(chan); + Serial.print(":" ); + Serial.print(volume); + Serial.print(":" ); + Serial.println(freq); + */ +} + +void emu_sndPlayBuzz(int size, int val) { + mymixer.buzz(size,val); + //Serial.print((val==1)?1:0); + //Serial.print(":"); + //Serial.println(size); +} +#endif + +/******************************** + * Initialization +********************************/ +void emu_init(int hires) { Serial.begin(115200); + vgahires = hires; -#ifdef HAS_USBKEY +#ifdef HAS_USB myusb.begin(); +#ifdef HAS_USBKEY keyboard1.attachPress(OnPress); keyboard1.attachRelease(OnRelease); #endif +#endif - while (!SD.begin(SD_CS)) +#ifdef FILEBROWSER + if (!SD.begin(SD_CS)) { - Serial.println("SD begin failed, retrying..."); - delay(1000); + Serial.println("No SD card detected"); } strcpy(selection,ROMSDIR); - FileHandlersInit(); - nbFiles = readNbFiles(); - - Serial.print("SD initialized, files found: "); Serial.println(nbFiles); +#endif emu_InitJoysticks(); #ifdef SWAP_JOYSTICK - joySwapped = true; + joySwapped = true; #else - joySwapped = false; + joySwapped = false; #endif -#ifdef TEECOMPUTER -#ifndef HAS_T4_VGA - tft.flipscreen(false); -#endif -#endif int keypressed = emu_ReadKeys(); +#ifdef HAS_T4_VGA + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } +#else + int gfx_mode = CFG_VGA; // default +#ifdef FILEBROWSER + gfx_mode = emu_readGfxConfig(); +#endif + // Force VGA if UP pressed + if (keypressed & MASK_JOY2_UP) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("VGA"); +#endif + gfx_mode = CFG_VGA; + } + else { + if (keypressed & MASK_JOY2_LEFT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ST"); +#endif + gfx_mode = CFG_ST; + } + else if (keypressed & MASK_JOY2_RIGHT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ILI"); +#endif + gfx_mode = CFG_ILI; + } + } + if (gfx_mode == CFG_VGA) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + else + { + tft.begin(gfx_mode == CFG_ILI?MODE_TFTILI_320x240:MODE_TFTST_320x240); + } +#endif + if (keypressed & MASK_JOY2_DOWN) { tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) ); tft.drawTextNoDma(64,48, (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); +#ifdef FILEBROWSER emu_eraseConfig(); delay(1000); +#endif } else { +#ifdef FILEBROWSER if (emu_readConfig()) { autorun = true; } +#endif } +#ifdef FILEBROWSER toggleMenu(true); +#endif } -void emu_start(void) +void emu_start(int vblms, void * callback, int forcetimervsync) { + vgatimervsync = forcetimervsync?true:false; + tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); + tft.startRefresh(); + if (callback != nullptr) { + vblCallback = callback; + } + + myTimer.begin(vblCount, vblms); +#ifdef HAS_SND + emu_sndInit(); +#endif usbnavpad = 0; } diff --git a/MCUME_teensy41/teensyo2em/emuapi.h b/MCUME_teensy41/teensyo2em/emuapi.h index 3fa6b6c..5dd6130 100644 --- a/MCUME_teensy41/teensyo2em/emuapi.h +++ b/MCUME_teensy41/teensyo2em/emuapi.h @@ -2,124 +2,14 @@ #define EMUAPI_H #include "platform_config.h" - -//#define TIMER_REND 1 -#define EXTRA_HEAP 0x10 - -// Title: < > -#define TITLE " Oddysey Emulator" -#define ROMSDIR "o2em" - - -#define emu_Init(ROM) {odd_Init();odd_Start(ROM);} -#define emu_Step() {odd_Step();} -#define emu_Input(x) {odd_Input(x);} - -#define MAX_FILENAME_PATH 64 -#define NB_FILE_HANDLER 4 -#define VID_FRAME_SKIP 0x0 -#define PALETTE_SIZE 256 -#define TFT_VBUFFER_YCROP 20 - -#define R32(rgb) ((rgb>>16)&0xff) -#define G32(rgb) ((rgb>>8)&0xff) -#define B32(rgb) (rgb & 0xff) +#include "emucfg.h" #define ACTION_NONE 0 -#define ACTION_MAXKBDVAL 16 -#define ACTION_EXITKBD 128 -#define ACTION_RUN1 129 -#define ACTION_RUN2 130 -#define ACTION_RUN3 131 - -#ifdef KEYMAP_PRESENT - -#define keylables_map0_0 (char *)"qwertyuiop\x1a" -#define keylables_map0_1 (char *)" asdfghjkl\x19" -#define keylables_map0_2 (char *)" zxcvbnm,.;/" -#define keylables_map0_3 (char *)" +\x10-" -const unsigned short key_map0[] = { - 'q','w','e','r','t','y','u','i','o','p',157, //lowecase - 0,'a','s','d','f','g','h','j','k','l',0x0D, - 0,'z','x','c','v','b','n','m',',','.',';','/', - 145,157,29,17, - 0,'+',' ','-' - }; - -#define keylables_map1_0 (char *)"QWERTYUIOP@" -#define keylables_map1_1 (char *)" ASDFGHJKL\x19" -#define keylables_map1_2 (char *)" ZXCVBNM<>:?" -#define keylables_map1_3 (char *)" =\x10_" -const unsigned short key_map1[] = { - 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase - 0,'A','S','D','F','G','H','J','K','L',0x0D, - 0,'Z','X','C','V','B','N','M','<','>',':','?', - 145,157,29,17, - 0,'=',' ','_' - }; - -#define keylables_map2_0 (char *)"!\"#$%^&*()@" -#define keylables_map2_1 (char *)" |\\[]{} " -#define keylables_map2_2 (char *)" <>:?" -#define keylables_map2_3 (char *)" =\x10_" -const unsigned short key_map2[] = { - '!','"','#','$','%','^','&','*','(',')','@', // shiftothers - 0, '|','\\','[',']','{','}','\'',0,0,0, - 0, 0,0,0,0,0,0,0,'<','>',':','?', - 0,0,0,0, - 0,'=',' ','_' - }; - -#define keylables_map3_0 (char *)"1234567890 " -#define keylables_map3_1 (char *)" " -#define keylables_map3_2 (char *)" " -#define keylables_map3_3 (char *)" " - -const unsigned short key_map3[] = { - '1','2','3','4','5','6','7','8','9','0',0, // digit keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map4_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " -#define keylables_map4_1 (char *)" " -#define keylables_map4_2 (char *)" " -#define keylables_map4_3 (char *)" " - -const unsigned short key_map4[] = { - 133,134,135,136,137,138,139,140,0,0,0, // function keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map5_0 (char *)" " -#define keylables_map5_1 (char *)" " -#define keylables_map5_2 (char *)" " -#define keylables_map5_3 (char *)" " - -const unsigned short key_map5[] = { - 0,0,0,0,0,0,0,0,0,0,0, // extra keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -const unsigned short matkeys[] = { - 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 - 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 - 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 - 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN - 0x510,0x010,0x110,0x310, // row 4 - }; - -#endif - +#define ACTION_RUN1 1 +#define ACTION_RUN2 2 +#define FORCE_VGATIMERVSYNC 1 +#define SUPPORT_HIRES 1 #define MASK_JOY2_RIGHT 0x0001 #define MASK_JOY2_LEFT 0x0002 @@ -136,24 +26,25 @@ const unsigned short matkeys[] = { #define MASK_JOY1_BTN 0x1000 #define MASK_KEY_USER4 0x2000 +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) #ifdef __cplusplus extern "C" { -#else -#define bool unsigned char +extern void emu_init(int hires=0); +extern void emu_start(int vblms, void * callback, int forcetimervsync=0); #endif - -extern void emu_init(void); -extern void emu_start(void); extern void emu_printf(const char * text); extern void emu_printi(int val); extern void emu_printh(int val); extern void * emu_Malloc(unsigned int size); extern void * emu_MallocI(unsigned int size); extern void emu_Free(void * pt); +extern void * emu_SMalloc(unsigned int size); +extern void emu_SFree(void * pt); extern int emu_FileOpen(const char * filepath, const char * mode); extern int emu_FileRead(void * buf, int size, int handler); +extern int emu_FileWrite(void * buf, int size, int handler); extern int emu_FileGetc(int handler); extern int emu_FileSeek(int handler, int seek, int origin); extern int emu_FileTell(int handler); @@ -164,24 +55,23 @@ extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size); extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek); extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index); -extern void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride); -extern void emu_DrawLine(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line); extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line); +extern void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride); extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line); -extern void emu_CopyLine(int width, int height, int ysrc, int ydst); extern void emu_DrawVsync(void); extern int emu_FrameSkip(void); -extern void * emu_LineBuffer(int line); -extern void emu_tweakVideo(int shiftdelta, int numdelta, int denomdelta); +extern int emu_IsVga(void); +extern int emu_IsVgaHires(void); -extern bool menuActive(void); +extern int menuActive(void); extern char * menuSelection(void); extern char * menuSecondSelection(void); -extern void toggleMenu(bool on); +extern void toggleMenu(int on); extern int handleMenu(unsigned short bClick); extern int handleOSKB(void); -extern void toggleOSKB(bool forceon); +extern void toggleOSKB(int forceon); extern void emu_InitJoysticks(void); extern int emu_SwapJoysticks(int statusOnly); @@ -190,6 +80,7 @@ extern int emu_ReadKeys(void); extern int emu_GetPad(void); extern int emu_GetMouse(int *x, int *y, int *buts); extern int emu_MouseDetected(void); +extern int emu_GetJoystick(void); extern int emu_KeyboardDetected(void); extern int emu_ReadAnalogJoyX(int min, int max); extern int emu_ReadAnalogJoyY(int min, int max); diff --git a/MCUME_teensy41/teensyo2em/emucfg.h b/MCUME_teensy41/teensyo2em/emucfg.h new file mode 100644 index 0000000..4a3f2b0 --- /dev/null +++ b/MCUME_teensy41/teensyo2em/emucfg.h @@ -0,0 +1,115 @@ +#ifndef EMUCFG_H +#define EMUCFG_H + +#include "wrapemu.h" + +// Title: < > +#define TITLE " Oddysey Emulator" +#define ROMSDIR "o2em" + +#define emu_Init(ROM) {odd_Init();odd_Start(ROM);} +#define emu_Step() {odd_Step();} +#define emu_Input(x) {odd_Input(x);} + +#define MAX_FILENAME_PATH 64 +#define NB_FILE_HANDLER 4 + +#define PALETTE_SIZE 256 +#define VID_FRAME_SKIP 0x0 +#define TFT_VBUFFER_YCROP 0 +#define SINGLELINE_RENDERING 1 +//#define CUSTOM_SND 1 +//#define TIMER_REND 1 +//#define EXTPAD 1 +#define EXTRA_HEAP 0x10 +#define FILEBROWSER 1 + + +#ifdef KEYMAP_PRESENT + +#define keylables_map0_0 (char *)"qwertyuiop\x1a" +#define keylables_map0_1 (char *)" asdfghjkl\x19" +#define keylables_map0_2 (char *)" zxcvbnm,.;/" +#define keylables_map0_3 (char *)" +\x10-" +const unsigned short key_map0[] = { + 'q','w','e','r','t','y','u','i','o','p',157, //lowecase + 0,'a','s','d','f','g','h','j','k','l',0x0D, + 0,'z','x','c','v','b','n','m',',','.',';','/', + 145,157,29,17, + 0,'+',' ','-' + }; + +#define keylables_map1_0 (char *)"QWERTYUIOP@" +#define keylables_map1_1 (char *)" ASDFGHJKL\x19" +#define keylables_map1_2 (char *)" ZXCVBNM<>:?" +#define keylables_map1_3 (char *)" =\x10_" +const unsigned short key_map1[] = { + 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase + 0,'A','S','D','F','G','H','J','K','L',0x0D, + 0,'Z','X','C','V','B','N','M','<','>',':','?', + 145,157,29,17, + 0,'=',' ','_' + }; + +#define keylables_map2_0 (char *)"!\"#$%^&*()@" +#define keylables_map2_1 (char *)" |\\[]{} " +#define keylables_map2_2 (char *)" <>:?" +#define keylables_map2_3 (char *)" =\x10_" +const unsigned short key_map2[] = { + '!','"','#','$','%','^','&','*','(',')','@', // shiftothers + 0, '|','\\','[',']','{','}','\'',0,0,0, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 0,0,0,0, + 0,'=',' ','_' + }; + +#define keylables_map3_0 (char *)"1234567890 " +#define keylables_map3_1 (char *)" " +#define keylables_map3_2 (char *)" " +#define keylables_map3_3 (char *)" " + +const unsigned short key_map3[] = { + '1','2','3','4','5','6','7','8','9','0',0, // digit keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map4_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " +#define keylables_map4_1 (char *)" " +#define keylables_map4_2 (char *)" " +#define keylables_map4_3 (char *)" " + +const unsigned short key_map4[] = { + 133,134,135,136,137,138,139,140,0,0,0, // function keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map5_0 (char *)" " +#define keylables_map5_1 (char *)" " +#define keylables_map5_2 (char *)" " +#define keylables_map5_3 (char *)" " + +const unsigned short key_map5[] = { + 0,0,0,0,0,0,0,0,0,0,0, // extra keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +const unsigned short matkeys[] = { + 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 + 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 + 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 + 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN + 0x510,0x010,0x110,0x310, // row 4 + }; + +#endif + +#endif diff --git a/MCUME_teensy41/teensyo2em/platform_config.h b/MCUME_teensy41/teensyo2em/platform_config.h index cad8176..0c3ab76 100644 --- a/MCUME_teensy41/teensyo2em/platform_config.h +++ b/MCUME_teensy41/teensyo2em/platform_config.h @@ -4,13 +4,11 @@ #define TEECOMPUTER 1 #ifdef TEECOMPUTER -//#define ILI9341 1 -//#define ST7789 1 -//#define TFTSPI1 1 -#define HAS_T4_VGA 1 +#define TFTSPI1 1 +//#define HAS_T4_VGA 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 -#define INVX 1 #define PT8211 1 #else @@ -19,7 +17,9 @@ #define INVX 1 #define INVY 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 +#define PT8211 1 #endif diff --git a/MCUME_teensy41/teensyo2em/t4_dsp.cpp b/MCUME_teensy41/teensyo2em/t4_dsp.cpp new file mode 100644 index 0000000..43301fa --- /dev/null +++ b/MCUME_teensy41/teensyo2em/t4_dsp.cpp @@ -0,0 +1,1774 @@ +/* + TFT/VGA driver + DMA TFT driver based on C64 ILI9341 dma driver from Frank Bösing, 2017 +*/ + +#include "T4_DSP.h" + +#include +#include + +#include "font8x8.h" + +// TFT constants and variables +#define TFT_LINEARINT 1 +#define LINEARINT_HACK 1 +#define DMA_LINES_PER_BLOCK 64 +#define DMA_NUM_SETTINGS 4 + +#define TFT_SWRESET 0x01 +#define TFT_SLPOUT 0x11 +#define TFT_INVON 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_MADCTL 0x36 +#define TFT_PIXFMT 0x3A +#define TFT_MADCTL_MY 0x80 +#define TFT_MADCTL_MX 0x40 +#define TFT_MADCTL_MV 0x20 +#define TFT_MADCTL_ML 0x10 +#define TFT_MADCTL_RGB 0x00 +#define TFT_MADCTL_BGR 0x08 +#define TFT_MADCTL_MH 0x04 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) +//#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) +//#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) +//#define R16(rgb) ((rgb>>8)&0xf8) +//#define G16(rgb) ((rgb>>3)&0xfc) +//#define B16(rgb) ((rgb<<3)&0xf8) + +// LPSPI4 = SPI0 in Teensy 4.0 +// LPSPI3 = SPI1 in Teensy 4.0 +// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) + +#ifdef TFTSPI1 +#define SPI SPI1 +#define LPSPIP_TDR LPSPI3_TDR +#define LPSPIP_CR LPSPI3_CR +#define LPSPIP_CFGR1 LPSPI3_CFGR1 +#define LPSPIP_TCR LPSPI3_TCR +#define LPSPIP_DER LPSPI3_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX +#else +#define LPSPIP_TDR LPSPI4_TDR +#define LPSPIP_CR LPSPI4_CR +#define LPSPIP_CFGR1 LPSPI4_CFGR1 +#define LPSPIP_TCR LPSPI4_TCR +#define LPSPIP_DER LPSPI4_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX +#endif + +#define SPICLOCK 60000000 +#define SPI_MODE SPI_MODE0 + +// VGA constants and macros +typedef uint8_t vga_pixel; +#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) + +static DMASetting dmasettings[DMA_NUM_SETTINGS]; +static DMAChannel dmatx; +static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K +static volatile uint8_t rstop = 0; +static volatile bool cancelled = false; +static volatile uint8_t curTransfer = 0; +static uint8_t nbTransfer = 0; +static uint16_t * tft_buffer; +static int tft_width; +static int tft_height; +static int tft_stride; + +#define DELAY_MASK 0x80 +PROGMEM static const uint8_t init_commands[] = { + 1+DELAY_MASK, TFT_SWRESET, 150, + 1+DELAY_MASK, TFT_SLPOUT, 255, + 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, + 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, + 1, TFT_INVON, + 1, TFT_DISPON, + 0 +}; + +// VGA constants and variables +// Objective: +// generates VGA signal fully in hardware with as little as possible CPU help + +// Principle: +// QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) +// 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate +// RGB out, combined to create 8bits(/12bits) output. + +// Note: +// - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels +// - experimental resolution: 352x240,352x480 +// - experimental resolution: 512x240,512x480 (not stable) +// - video memory is allocated using malloc in T4 heap +// - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing +// but tried to be compensated by pixel shifting +// - Default is 8bits RRRGGGBB (332) +// But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! +// - Only ok at 600MHz else some disturbances visible + + + +#define TOP_BORDER 40 +#define PIN_HBLANK 15 + +#define PIN_R_B2 33 +#define PIN_R_B1 4 +#define PIN_R_B0 3 +#define PIN_G_B2 2 +#define PIN_G_B1 13 +#define PIN_G_B0 11 +#define PIN_B_B1 12 +#define PIN_B_B0 10 + + +#define DMA_HACK 0x80 + +#define R16(rgb) ((rgb>>8)&0xf8) +#define G16(rgb) ((rgb>>3)&0xfc) +#define B16(rgb) ((rgb<<3)&0xf8) + +// VGA 640x480@60Hz +// Screen refresh rate 60 Hz +// Vertical refresh 31.46875 kHz +// Pixel freq. 25.175 MHz +// +// Visible area 640 25.422045680238 us +// Front porch 16 0.63555114200596 us +// Sync pulse 96 3.8133068520357 us +// Back porch 48 1.9066534260179 us +// Whole line 800 31.777557100298 us + +#define frame_freq 60.0 // Hz +#define line_freq 31.46875 // KHz +#define pix_freq (line_freq*800) // KHz (25.175 MHz) + +// pix_period = 39.7ns +// H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) +#define frontporch_pix 20 //16 +#define backporch_pix 44 //48 + +// Flexio Clock +// PLL3 SW CLOCK (3) => 480 MHz +// PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) +#define FLEXIO_CLK_SEL_PLL3 3 +#define FLEXIO_CLK_SEL_PLL5 2 + +/* Set video PLL */ +// There are /1, /2, /4, /8, /16 post dividers for the Video PLL. +// The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, +// and CCM_ANALOG_MISC2 register sets according to the following equation. +// PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + +// nfact: +// This field controls the PLL loop divider. +// Valid range for DIV_SELECT divider value: 27~54. + +#define POST_DIV_SELECT 2 + +// Full buffer including back/front porch +static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; +static uint32_t dstbuffer __attribute__((aligned(32))); + +// Visible vuffer +static vga_pixel * vga_buffer; +static int vga_width; +static int vga_height; +static int vga_stride; + +static int maxpixperline; +static int left_border; +static int right_border; +static int line_double; +static int pix_shift; +static int ref_div_select; +static int ref_freq_num; +static int ref_freq_denom; +static int ref_pix_shift; +static int combine_shiftreg; + +#ifdef DEBUG +static uint32_t ISRTicks_prev = 0; +volatile uint32_t ISRTicks = 0; +#endif + +uint8_t T4_DSP::_rst; +uint8_t T4_DSP::_cs; +uint8_t T4_DSP::_dc; +uint8_t T4_DSP::_mosi; +uint8_t T4_DSP::_sclk; +uint8_t T4_DSP::_vsync_pin = -1; +DMAChannel T4_DSP::flexio1DMA; +DMAChannel T4_DSP::flexio2DMA; + +static volatile uint32_t VSYNC = 0; +static volatile uint32_t currentLine=0; +#define NOP asm volatile("nop\n\t"); +static gfx_mode_t gfxmode = MODE_UNDEFINED; + + +FASTRUN void T4_DSP::TFT_isr(void) { + dmatx.clearInterrupt(); + curTransfer++; + if (curTransfer >= nbTransfer) { + curTransfer = 0; + if (cancelled) { + dmatx.disable(); + rstop = 1; + } + } + arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); +} + +FASTRUN void T4_DSP::QT3_isr(void) { + TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); + TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); + + cli(); + + // V-PULSE + if (currentLine > 0) { + digitalWrite(_vsync_pin, 1); + VSYNC = 0; + } else { + digitalWrite(_vsync_pin, 0); + VSYNC = 1; + } + + currentLine++; + currentLine = currentLine % 525; + + + uint32_t y = (currentLine - TOP_BORDER) >> line_double; + // Visible area + + if (y >= 0 && y < vga_height) { + // Disable DMAs + //DMA_CERQ = flexio2DMA.channel; + //DMA_CERQ = flexio1DMA.channel; + + // Setup source adress + // Aligned 32 bits copy + unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; + flexio2DMA.TCD->SADDR = p; + if (pix_shift & DMA_HACK) + { + // Unaligned copy + uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; + flexio1DMA.TCD->SADDR = p2; + } + else { + p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 + flexio1DMA.TCD->SADDR = p; + } + + // Enable DMAs + //flexio2DMA.enable(); + //flexio1DMA.enable(); + DMA_SERQ = flexio2DMA.channel; + DMA_SERQ = flexio1DMA.channel; + arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); + } + sei(); + +#ifdef DEBUG + ISRTicks++; +#endif + asm volatile("dsb"); +} + +static void setDmaStruct() { + uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; + uint16_t * fb = (uint16_t*)malloc(remaining); + tft_buffer = fb; + tft_width = TFT_WIDTH; + tft_height = TFT_HEIGHT; + tft_stride = TFT_WIDTH; + uint16_t col=RGBVAL16(0x00,0x00,0x00); + int i=0; + while (remaining > 0) { + int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); + blocks[i] = fb; + for (int j=0;jATTR_DST = 1; + dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); + dmasettings[i].interruptAtCompletion(); + fb += len/2; + remaining -= len; + i++; + } + dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); + nbTransfer = i; +} + +static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 +{ +//if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; + CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE + | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 + | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); + CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; + CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock + const int div_post_pll = 1; // other values: 2,4 + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass +} + +T4_DSP::T4_DSP() +{ + _cs = TFT_CS; + _dc = TFT_DC; + _rst = TFT_RST; + _mosi = TFT_MOSI; + _sclk = TFT_SCLK; + pinMode(_dc, OUTPUT); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, 1); + digitalWrite(_dc, 1); + _vsync_pin = 8; +} + + +void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { + int dx=0; + int dy=0; + digitalWrite(_dc, 0); + SPI.transfer(TFT_CASET); + digitalWrite(_dc, 1); + SPI.transfer16(x1+dx); + digitalWrite(_dc, 1); + SPI.transfer16(x2+dx); + digitalWrite(_dc, 0); + SPI.transfer(TFT_PASET); + digitalWrite(_dc, 1); + SPI.transfer16(y1+dy); + digitalWrite(_dc, 1); + SPI.transfer16(y2+dy); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + return; +} + +void T4_DSP::tft_setup(bool isST) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + // RESET if reset pin defined + if (_rst != 0xff) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + const uint8_t *addr = init_commands; + uint8_t count; + digitalWrite(_cs, 0); + while (count = *addr++) { + uint8_t command = *addr++; + if ( (command == TFT_INVON) && (!isST) ) { + // Skip TFT_INVON for ILI + } + else { + digitalWrite(_dc, 0); // command + SPI.transfer(command); + uint16_t ms = count & DELAY_MASK; + count &= ~DELAY_MASK; + while (--count > 0) { // data + uint8_t data = *addr++; + if ( (command == TFT_MADCTL) && (isST) ) { + data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; + } + digitalWrite(_dc, 1); + SPI.transfer(data); + } + if (ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + digitalWrite(_cs, 1); + SPI.endTransaction(); + delay(2); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + } + } + } + digitalWrite(_cs, 1); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + SPI.endTransaction(); + /* + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_dc, 0); + digitalWrite(_cs, 0); + SPI.transfer(TFT_MADCTL); + digitalWrite(_dc, 1); + SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); + // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); + digitalWrite(_cs, 1); + SPI.endTransaction(); + */ + cancelled = false; +} + +// display VGA image +gfx_error_t T4_DSP::begin(gfx_mode_t mode) +{ + uint32_t flexio_clock_div; + combine_shiftreg = 0; +// int div_select = 49; +// int num = 135; +// int denom = 100; + int div_select = 20; + int num = 9800; + int denom = 10000; + int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; + int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; + set_videoClock(div_select,num,denom,true); + +#ifdef DEBUG + Serial.println(mode); + Serial.println("mode"); +#endif + + switch(mode) + { + case MODE_TFTILI_320x240: +#ifdef DEBUG + Serial.println("TFTILI_320x240"); +#endif + tft_setup(false); + gfxmode = mode; + break; + case MODE_TFTST_320x240: +#ifdef DEBUG + Serial.println("TFTST_320x240"); +#endif + tft_setup(true); + gfxmode = mode; + break; + + case MODE_VGA_320x240: +#ifdef DEBUG + Serial.println("VGA_320x240"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_320x480: +#ifdef DEBUG + Serial.println("VGA_320x480"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_640x240: +#ifdef DEBUG + Serial.println("VGA_640x240"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/pix_freq; + line_double = 1; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_640x480: +#ifdef DEBUG + Serial.println("VGA_640x480"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = (flexio_freq/pix_freq); + line_double = 0; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_512x240: +#ifdef DEBUG + Serial.println("VGA_512x240"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 1; + pix_shift = 0; + break; + + case MODE_VGA_512x480: +#ifdef DEBUG + Serial.println("VGA_512x480"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 0; + pix_shift = 0; + break; + + case MODE_VGA_352x240: +#ifdef DEBUG + Serial.println("VGA_352x240"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_352x480: +#ifdef DEBUG + Serial.println("VGA_352x480"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + } + + if (mode >= MODE_VGA_320x240) + { + if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { + fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); + digitalWrite(_cs, 0); + digitalWrite(_dc, 0); + SPI.transfer(TFT_DISPOFF); + digitalWrite(_cs, 1); + delay(20); + digitalWrite(_cs, 0); + digitalWrite(_cs, 1); + } + gfxmode = mode; + + maxpixperline = vga_stride; + // Save param for tweek adjustment + ref_div_select = div_select; + ref_freq_num = num; + ref_freq_denom = denom; + ref_pix_shift = pix_shift; + +#ifdef DEBUG + Serial.println("frequency"); + Serial.println(flexio_freq); + Serial.println("div"); + Serial.println(flexio_freq/pix_freq); +#endif + + pinMode(_vsync_pin, OUTPUT); + pinMode(PIN_HBLANK, OUTPUT); + + /* Basic pin setup FlexIO1 */ + pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 + pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 + pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 + pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 + /* Basic pin setup FlexIO2 */ + pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 + pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 + pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 + pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 + + /* High speed and drive strength configuration */ + *(portControlRegister(PIN_G_B2)) = 0xFF; + *(portControlRegister(PIN_R_B0)) = 0xFF; + *(portControlRegister(PIN_R_B1)) = 0xFF; + *(portControlRegister(PIN_R_B2)) = 0xFF; + *(portControlRegister(PIN_B_B0)) = 0xFF; + *(portControlRegister(PIN_B_B1)) = 0xFF; + *(portControlRegister(PIN_G_B0)) = 0xFF; + *(portControlRegister(PIN_G_B1)) = 0xFF; + + /* Set clock for FlexIO1 and FlexIO2 */ + CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) + | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); + CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) + | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); + + + /* Set up pin mux FlexIO1 */ + *(portConfigRegister(PIN_G_B2)) = 0x14; + *(portConfigRegister(PIN_R_B0)) = 0x14; + *(portConfigRegister(PIN_R_B1)) = 0x14; + *(portConfigRegister(PIN_R_B2)) = 0x14; + /* Set up pin mux FlexIO2 */ + *(portConfigRegister(PIN_B_B0)) = 0x14; + *(portConfigRegister(PIN_B_B1)) = 0x14; + *(portConfigRegister(PIN_G_B0)) = 0x14; + *(portConfigRegister(PIN_G_B1)) = 0x14; + + /* Enable the clock */ + CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + /* Enable the FlexIO with fast access */ + FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + + uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; + uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; + + /* Shifter 0 registers for FlexIO2 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 + inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter + stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled + startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable + timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 + timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock + pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output + pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity + shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode + /* Shifter 0 registers for FlexIO1 */ + FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + /* Shifter 0 registers for FlexIO1 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 + FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + if (combine_shiftreg) { + pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled + FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + } + /* Timer 0 registers for FlexIO2 */ + timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset + timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output + timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset + timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare + timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert + stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled + startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled + if (combine_shiftreg) { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag + } + else { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag + } + triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low + triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected + pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled + //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 + //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high + timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode + // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) + + int shifts_per_transfer; + if (combine_shiftreg) { + shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 + } + else { + shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 + } + FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); + /* Timer 0 registers for FlexIO1 */ + FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); +#ifdef DEBUG + Serial.println("FlexIO setup complete"); +#endif + + /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ + if (combine_shiftreg) { + FLEXIO2_SHIFTSDEN |= (1<<1); + FLEXIO1_SHIFTSDEN |= (1<<1); + } + else { + FLEXIO2_SHIFTSDEN |= (1<<0); + FLEXIO1_SHIFTSDEN |= (1<<0); + } + /* Disable DMA channel so it doesn't start transferring yet */ + flexio1DMA.disable(); + flexio2DMA.disable(); + /* Set up DMA channel to use Shifter 0 trigger */ + flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); + flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); + + + if (combine_shiftreg) { + flexio2DMA.TCD->NBYTES = 8; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 8; + flexio2DMA.TCD->CITER = maxpixperline / 8; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + flexio1DMA.TCD->NBYTES = 8; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 8; + flexio1DMA.TCD->CITER = maxpixperline / 8; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Setup DMA2 Flexio2 copy + flexio2DMA.TCD->NBYTES = 4; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 4; + flexio2DMA.TCD->CITER = maxpixperline / 4; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + // Setup DMA1 Flexio1 copy + // Use pixel shift to avoid color smearing? + if (pix_shift & DMA_HACK) + { + if (pix_shift & 0x3 == 0) { + // Aligned 32 bits copy (32bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Unaligned (source) 32 bits copy (8bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 1; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion + } + } + else + { + // Aligned 32 bits copy + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + } + +#ifdef DEBUG + Serial.println("DMA setup complete"); +#endif + + // enable clocks for QTIMER3: generates the 15KHz for hsync + // Pulse: + // low : 3.8133 us => 569x6.7ns + // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) + // (OLD TEST) + // (4us low, 28us high => 32us) + // (597x6.7ns for 4us) + // (4179x6.7ns for 28us) + CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 + //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 + + #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz + #define MARGIN_D 1000 + + TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer + // Invert output pin as we want the interupt on rising edge + TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) + TMR3_CNTR3 = 0; + TMR3_LOAD3 = 0; + + /* Inverted timings */ + unsigned long long cpu_freq = F_CPU; + unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; + int rate2 = rate; + + int substract = 1; + if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { + substract=5; + rate2=1652; + } + + #ifdef DEBUG + Serial.print("MARGIN_N is: "); + Serial.println(rate2, DEC); + Serial.print("SUBSTRACT is: "); + Serial.println(substract, DEC); +#endif + TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; + TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; + /* + TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; + */ + TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on + TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), + // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) + //configure Teensy pin Compare output + IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 + attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function + NVIC_ENABLE_IRQ(IRQ_QTIMER3); +#ifdef DEBUG + Serial.println("QTIMER3 setup complete"); + Serial.print("V-PIN is "); + Serial.println(_vsync_pin); +#endif + + /* initialize gfx buffer */ + if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift + if (gfxbuffer == NULL) return(GFX_ERROR); +#ifdef DEBUG + Serial.println("Memory allocated"); +#endif + + memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); + vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; +#ifdef DEBUG + Serial.println(vga_stride); + Serial.println(vga_height); + Serial.println("Screen cleared"); +#endif + } + + return(GFX_OK); +} + +gfx_mode_t T4_DSP::getMode(void) +{ + return gfxmode; +} + +void T4_DSP::startRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + curTransfer = 0; + rstop = 0; + //dmatx.begin(true); + dmatx.attachInterrupt(TFT_isr); + setDmaStruct(); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + + digitalWrite(_cs, HIGH); + SPI.begin(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + + LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: + LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX + LPSPIP_TCR = 15; // Framesize 16 Bits + //LPSPIP_FCR = 0; // Fifo Watermark + LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable + LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: + dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); + + dmatx = dmasettings[0]; + digitalWrite(_cs, 0); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + dmatx.enable(); + } +} + + +void T4_DSP::stopRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + rstop = 1; + unsigned long m = millis(); + cancelled = true; + while (!rstop) { + if ((millis() - m) > 100) break; + delay(10); + asm volatile("wfi"); + }; + rstop = 0; + delay(50); + cancelled = false; + dmatx.detachInterrupt(); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + SPI.end(); +#ifdef ST7789 +// begin(gfxmode); +#endif + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + } +} + +int T4_DSP::get_frame_buffer_size(int *width, int *height) { + if (gfxmode < MODE_VGA_320x240) { + if (width != nullptr) *width = tft_width; + if (height != nullptr) *height = tft_height; + return tft_stride; + } + else { + if (width != nullptr) *width = vga_width; + if (height != nullptr) *height = vga_height; + return vga_stride; + } +} + +void T4_DSP::waitSync() +{ + if (gfxmode >= MODE_VGA_320x240) { + while (VSYNC == 0) {}; + } +} + +void T4_DSP::waitLine(int line) +{ + if (gfxmode >= MODE_VGA_320x240) { + while (currentLine != line) {}; + } +} + +/*********************************************************************************************** + No DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreenNoDma(uint16_t color) { + if (gfxmode < MODE_VGA_320x240) { + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + int i,j; + for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(arx, ary, arx+arw-1, ary+arh-1); + bitmap = bitmap + bmp_offy*w + bmp_offx; + for (int row=0;row> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + bits = *charpt++; + //digitalWrite(_dc, 1); + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + x +=8; + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + else { + drawText(x, y, text, fgcolor, bgcolor, doublesize); + } +} + + +/*********************************************************************************************** + DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreen(uint16_t color) { + int i,j; + if (gfxmode < MODE_VGA_320x240) { + for (j=0; j> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + dst=&tft_buffer[l*tft_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + x +=8; + } + } + else { + vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); + vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); + vga_pixel * dst; + while ((c = *text++)) { + const unsigned char * charpt=&font8x8[c][0]; + int l=y; + for (int i=0;i<8;i++) + { + unsigned char bits; + if (doublesize) { + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + x +=8; + } + } +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { + drawSprite(x,y,bitmap, 0,0,0,0); +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) +{ + int bmp_offx = 0; + int bmp_offy = 0; + uint16_t *bmp_ptr; + int w =*bitmap++; + int h = *bitmap++; + if ( (arw == 0) || (arh == 0) ) { + // no crop window + arx = x; + ary = y; + arw = w; + arh = h; + } + else { + if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + int l=ary; + bitmap = bitmap + bmp_offy*w + bmp_offx; + + if (gfxmode < MODE_VGA_320x240) { + for (int row=0;row tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]; + pos +=step; + } + #endif + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i 2) ) y += (tft_height-height)/2; + uint16_t * dst=&tft_buffer[y*tft_stride]; + if (width > tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]]; + pos +=step; + } +#endif + } + else if ((width*2) == tft_width) { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]]; + *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i tft_width) { + int step = ((width << 8)/tft_width); + int pos = 0; + for (int i=0; i> 8]]; + pos +=step; + } + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = pix; + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i +#include +#endif + +#include "platform_config.h" +#include "iopins.h" + + + +#ifndef TFT_WIDTH +#define TFT_WIDTH 320 +#endif +#define TFT_REALWIDTH 320 + +#ifndef TFT_HEIGHT +#define TFT_HEIGHT 240 +#endif +#define TFT_REALHEIGHT 240 + + +typedef enum gfx_mode_t +{ + MODE_UNDEFINED = 0, + MODE_TFTILI_320x240 = 1, + MODE_TFTST_320x240 = 2, + MODE_VGA_320x240 = 3, + MODE_VGA_320x480 = 4, + MODE_VGA_352x240 = 5, + MODE_VGA_352x480 = 6, + MODE_VGA_512x240 = 7, + MODE_VGA_512x480 = 8, + MODE_VGA_640x240 = 9, + MODE_VGA_640x480 = 10 +} gfx_mode_t; + +typedef enum gfx_error_t +{ + GFX_OK = 0, + GFX_ERROR = -1 +} gfx_error_t; + + +#ifdef __cplusplus + +class T4_DSP +{ + public: + T4_DSP(); + + gfx_error_t begin(gfx_mode_t mode); + gfx_mode_t getMode(void); + void startRefresh(void); + void stopRefresh(); + + int get_frame_buffer_size(int *width, int *height); + void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); + + // wait next Vsync + void waitSync(); + void waitLine(int line); + + // NoDMA functions + void fillScreenNoDma(uint16_t color); + void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + // DMA functions + void fillScreen(uint16_t color); + void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + void writeLine(int width, int height, int y, uint16_t *buf); + void writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + void writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16); + void writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + + protected: + static uint8_t _rst, _cs, _dc; + static uint8_t _mosi, _sclk; + static uint8_t _vsync_pin; + static DMAChannel flexio1DMA; + static DMAChannel flexio2DMA; + void tft_setup(bool isST); + static void TFT_isr(void); + static void QT3_isr(void); +}; + +#endif +#endif diff --git a/MCUME_teensy41/teensyo2em/teensyo2em.ino b/MCUME_teensy41/teensyo2em/teensyo2em.ino index 0514744..1dd7986 100644 --- a/MCUME_teensy41/teensyo2em/teensyo2em.ino +++ b/MCUME_teensy41/teensyo2em/teensyo2em.ino @@ -3,135 +3,16 @@ extern "C" { #include "emuapi.h" } -extern "C" { -#include "Oddemu.h" -} - -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -TFT_T_DMA tft; -#else -#include "tft_t_dma.h" -TFT_T_DMA tft = TFT_T_DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, TFT_TOUCH_CS, TFT_TOUCH_INT); -#endif - -bool vgaMode = false; - -static unsigned char palette8[PALETTE_SIZE]; -static unsigned short palette16[PALETTE_SIZE]; -static IntervalTimer myTimer; -volatile boolean vbl=true; -static int skip=0; -static elapsedMicros tius; - -static void vblCount() { - if (vbl) { - vbl = false; - } else { - vbl = true; - } -} - -void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) -{ - if (index>8, - 320 & 0xFF, // YEND = 320 - ST7735_INVON , DELAY, // 7: hack - 10, - ST7735_NORON , DELAY, // 8: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 9: Main screen turn on, no args, w/delay - 255 -#endif -}; - -static void dmaInterrupt() { - dmatx.clearInterrupt(); - curTransfer++; - if (curTransfer >= nbTransfer) { - curTransfer = 0; - if (cancelled) { - dmatx.disable(); - rstop = 1; - } - } - arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2); -} - -static void setDmaStruct() { - uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; - int i=0; - uint16_t col=RGBVAL16(0x00,0x00,0x00);; - while (remaining > 0) { - uint16_t * fb = blocks[i]; - int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining); -#ifdef TFT_DEBUG - Serial.println((unsigned long)blocks[i]); - Serial.println(remaining); -#endif - switch (i) { - case 0: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb0[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0x00); -#endif - break; - case 1: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb1[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0xff); -#endif - break; - case 2: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb2[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0x00,0xff); -#endif - break; - case 3: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb3[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0xff,0x00,0xff); -#endif - break; - } - blocks[i] = fb; - if (blocks[i] == 0) { - Serial.print("ILI9341 allocaltion failed for block "); - Serial.println(i); - delay(10000); - } - - for (int j=0;jATTR_DST = 1; - dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); - dmasettings[i].interruptAtCompletion(); - remaining -= len; - i++; - } - dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); - nbTransfer = i; -#ifdef TFT_DEBUG - Serial.println(nbTransfer); -#endif -} - - -TFT_T_DMA::TFT_T_DMA(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso, uint8_t touch_cs, uint8_t touch_irq) -{ - _cs = cs; - _dc = dc; - _rst = rst; - _mosi = mosi; - _sclk = sclk; - _miso = miso; - pinMode(_dc, OUTPUT); - pinMode(_cs, OUTPUT); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); - if ( (touch_cs != 255) && (touch_irq != 255) ) { - _touch_irq = touch_irq; - _touch_cs = touch_cs; - pinMode(_touch_cs, OUTPUT); - pinMode(touch_irq, INPUT_PULLUP); - digitalWrite(_touch_cs, 1); - } -} - - -void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { - int dx=0; - int dy=0; -#ifdef ST7789 - if (TFT_REALWIDTH == TFT_REALHEIGHT) - { -#ifdef ROTATE_SCREEN - if (!flipped) { - dy += 80; - } -#else - if (flipped) { - dx += 80; - } -#endif - } -#endif - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - SPI.transfer16(x1+dx); - digitalWrite(_dc, 1); - SPI.transfer16(x2+dx); - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - digitalWrite(_dc, 1); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - return; - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - - SPI.transfer16(x1+dx); - SPI.transfer16(x2+dx); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - -void TFT_T_DMA::begin(void) { - SPI.setMOSI(_mosi); - SPI.setMISO(_miso); - SPI.setSCK(_sclk); - SPI.begin(); - - // Initialize display - if (_rst != 0xff) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - const uint8_t *addr = init_commands; - digitalWrite(_cs, 0); -#ifdef ILI9341 - while (1) { - uint8_t count = *addr++; - if (count-- == 0) break; - - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - - while (count-- > 0) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - } - - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(ILI9341_DISPON); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); -#endif -#ifdef ST7789 - uint8_t numCommands, numArgs; - uint16_t ms; - numCommands = *addr++; // Number of commands to follow - while(numCommands--) { // For each command... - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - numArgs = *addr++; // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs > 1) { // For each argument... - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - numArgs--; - } - - if (numArgs) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - if(ms) { - ms = *addr++; // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - digitalWrite(_cs, 1); - SPI.endTransaction(); - delay(ms); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - } - } - digitalWrite(_cs, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - SPI.endTransaction(); - - cancelled = false; - -#ifdef FLIP_SCREEN - flipscreen(true); -#else - flipscreen(false); -#endif -#ifdef ST7789 - if (TFT_REALWIDTH != TFT_REALHEIGHT) - { - flipscreen(true); - } -#endif -}; - - - -void TFT_T_DMA::flipscreen(bool flip) -{ - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(TFT_MADCTL); - digitalWrite(_dc, 1); - if (flip) { - flipped=true; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB); -#endif -#endif - } - else { - flipped=false; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB); -#endif -#endif - } - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - -boolean TFT_T_DMA::isflipped(void) -{ - return(flipped); -} - - -#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) - - -void TFT_T_DMA::startDMA(void) { - curTransfer = 0; - rstop = 0; - //dmatx.begin(true); - dmatx.attachInterrupt(dmaInterrupt); - setDmaStruct(); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - - digitalWrite(_cs, HIGH); - SPI.begin(); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); - - - LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: - LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX - LPSPIP_TCR = 15; // Framesize 16 Bits - //LPSPIP_FCR = 0; // Fifo Watermark - LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable - LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: - dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); - - dmatx = dmasettings[0]; - digitalWrite(_cs, 0); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - dmatx.enable(); -} - - -void TFT_T_DMA::stopDMA(void) { - rstop = 0; - wait(); - delay(50); - cancelled = false; - dmatx.detachInterrupt(); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - SPI.end(); -#ifdef ST7789 - begin(); -#endif -#ifdef ILI9341 - SPI.begin(); - digitalWrite(_cs, 0); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - SPI.endTransaction(); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); -} - -void TFT_T_DMA::wait(void) { - rstop = 1; - unsigned long m = millis(); - cancelled = true; - while (!rstop) { - if ((millis() - m) > 100) break; - delay(10); - asm volatile("wfi"); - }; - rstop = 0; -} - -int TFT_T_DMA::get_frame_buffer_size(int *width, int *height){ - if (width != nullptr) *width = TFT_REALWIDTH; - if (height != nullptr) *height = TFT_REALHEIGHT; - return TFT_REALWIDTH; -} - - -/*********************************************************************************************** - Touch functions - ***********************************************************************************************/ -/* Code based on ... - * - * @file XPT2046.cpp - * @date 19.02.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the XPT2046 driver for Arduino. - */ - -#define ADC_MAX 0x0fff - -void TFT_T_DMA::enableTouchIrq() -{ - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 }; - SPI.transfer((void*)&buf[0],3); - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); -} - -//Default callibration for non flipped -#define TX_MIN 30 -#define TY_MIN 20 -#define TX_MAX 300 -#define TY_MAX 220 - -//Default callibration for flipped -#define TFX_MIN 20 -#define TFY_MIN 25 -#define TFX_MAX 288 -#define TFY_MAX 221 - -static uint16_t txMin; -static uint16_t tyMin; -static uint16_t txMax; -static uint16_t tyMax; - - -void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { - if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) { - txMin = xMin; - tyMin = yMin; - txMax = xMax; - tyMax = yMax; - } - else { - if (flipped) { - txMin = TFX_MIN; - tyMin = TFY_MIN; - txMax = TFX_MAX; - tyMax = TFY_MAX; - } - else { - txMin = TX_MIN; - tyMin = TY_MIN; - txMax = TX_MAX; - tyMax = TY_MAX; - } - } -} - - -void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - if ( TOUCH_ENABLED() ) { - uint16_t x = 0; - uint16_t y = 0; - uint16_t z1 = 0; - uint16_t z2 = 0; - uint8_t i = 0; - int16_t xraw=0, yraw=0; - - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - - for(; i < 15; i++) { - // SPI requirer 32bit aliment - uint8_t buf[12] = { - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00 - }; - SPI.transfer(&buf[0], &buf[0], 12); - y += (buf[1] << 8 | buf[2])>>3; - x += (buf[4] << 8 | buf[5])>>3; - z1 += (buf[7] << 8 | buf[8])>>3; - z2 += (buf[10] << 8 | buf[11])>>3; - } - enableTouchIrq(); - - if(i == 0) { - *oX = 0; - *oY = 0; - *oZ = 0; - } - else { - x /= i; - y /= i; - z1 /= i; - z2 /= i; - } - - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); - int z = z1 + ADC_MAX - z2; - if (flipped) { - xraw = x; - yraw = y; - } else { - xraw = ADC_MAX - x; - yraw = ADC_MAX - y; - } - xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1); - yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1); - - *oX = xraw; - *oY = yraw; - *oZ = z; - } - else - { - *oX = 0; - *oY = 0; - *oZ = 0; - } -} - -void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - readRaw(oX,oY,oZ); - // callibrate ... - if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin); - if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin); - //Serial.print(*oX); - //Serial.print(" "); - //Serial.println(*oY); -} - - -/*********************************************************************************************** - No DMA functions - ***********************************************************************************************/ -void TFT_T_DMA::fillScreenNoDma(uint16_t color) { - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - int i,j; - for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(arx, ary, arx+arw-1, ary+arh-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - bits = *charpt++; - //digitalWrite(_dc, 1); - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - x +=8; -#ifdef ILI9341 - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); -#endif - digitalWrite(_cs, 1); - SPI.endTransaction(); - } - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - - - -/*********************************************************************************************** - DMA functions - ***********************************************************************************************/ -uint16_t * TFT_T_DMA::getLineBuffer(int j) -{ - uint16_t * block=blocks[j>>6]; - return(&block[(j&0x3F)*TFT_REALWIDTH]); -} - -void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) { - uint8_t *buffer=buf; - uint8_t *src; - - int i,j,y=0; - if (width*2 <= TFT_REALWIDTH) { - for (j=0; j>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH]; - for (i=0; i>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x]; - for (i=0; i>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - block=blocks[l>>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt++; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - x +=8; - } -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { - drawSprite(x,y,bitmap, 0,0,0,0); -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) -{ - int bmp_offx = 0; - int bmp_offy = 0; - uint16_t *bmp_ptr; - - int w =*bitmap++; - int h = *bitmap++; - - - if ( (arw == 0) || (arh == 0) ) { - // no crop window - arx = x; - ary = y; - arw = w; - arh = h; - } - else { - if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - int l=ary; - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx]; - bmp_ptr = (uint16_t*)bitmap; - for (int col=0;col -#include -#include -#endif - -#include "tft_t_dma_config.h" - -#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) -#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define R16(rgb) ((rgb>>8)&0xf8) -#define G16(rgb) ((rgb>>3)&0xfc) -#define B16(rgb) ((rgb<<3)&0xf8) - -#define PAL_COLOR_MASK 0xff - -#ifdef LOHRES -#define TFT_WIDTH 240 -#define TFT_REALWIDTH 240 -#else -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 -#endif -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - -//#define WIDTH 272 -//#define HEIGHT 228 - -#define LINES_PER_BLOCK 64 -#define NR_OF_BLOCK 4 -#define SCREEN_DMA_NUM_SETTINGS NR_OF_BLOCK - - -#ifdef ILI9341 - -#define ILI9341_NOP 0x00 -#define ILI9341_SWRESET 0x01 -#define ILI9341_RDDID 0x04 -#define ILI9341_RDDST 0x09 - -#define ILI9341_SLPIN 0x10 -#define ILI9341_SLPOUT 0x11 -#define ILI9341_PTLON 0x12 -#define ILI9341_NORON 0x13 - -#define ILI9341_RDMODE 0x0A -#define ILI9341_RDMADCTL 0x0B -#define ILI9341_RDPIXFMT 0x0C -#define ILI9341_RDIMGFMT 0x0D -#define ILI9341_RDSELFDIAG 0x0F - -#define ILI9341_INVOFF 0x20 -#define ILI9341_INVON 0x21 -#define ILI9341_GAMMASET 0x26 -#define ILI9341_DISPOFF 0x28 -#define ILI9341_DISPON 0x29 - -#define ILI9341_CASET 0x2A -#define ILI9341_PASET 0x2B -#define ILI9341_RAMWR 0x2C -#define ILI9341_RAMRD 0x2E - -#define ILI9341_PTLAR 0x30 -#define ILI9341_MADCTL 0x36 -#define ILI9341_VSCRSADD 0x37 -#define ILI9341_PIXFMT 0x3A - -#define ILI9341_FRMCTR1 0xB1 -#define ILI9341_FRMCTR2 0xB2 -#define ILI9341_FRMCTR3 0xB3 -#define ILI9341_INVCTR 0xB4 -#define ILI9341_DFUNCTR 0xB6 - -#define ILI9341_PWCTR1 0xC0 -#define ILI9341_PWCTR2 0xC1 -#define ILI9341_PWCTR3 0xC2 -#define ILI9341_PWCTR4 0xC3 -#define ILI9341_PWCTR5 0xC4 -#define ILI9341_VMCTR1 0xC5 -#define ILI9341_VMCTR2 0xC7 - -#define ILI9341_RDID1 0xDA -#define ILI9341_RDID2 0xDB -#define ILI9341_RDID3 0xDC -#define ILI9341_RDID4 0xDD - -#define ILI9341_GMCTRP1 0xE0 -#define ILI9341_GMCTRN1 0xE1 - -#define ILI9341_MADCTL_MY 0x80 -#define ILI9341_MADCTL_MX 0x40 -#define ILI9341_MADCTL_MV 0x20 -#define ILI9341_MADCTL_ML 0x10 -#define ILI9341_MADCTL_RGB 0x00 -#define ILI9341_MADCTL_BGR 0x08 -#define ILI9341_MADCTL_MH 0x04 - -#define TFT_CASET ILI9341_CASET -#define TFT_PASET ILI9341_PASET -#define TFT_RAMWR ILI9341_RAMWR -#define TFT_MADCTL ILI9341_MADCTL - -#endif - - -#ifdef ST7789 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_RGB 0x00 -#define ST77XX_MADCTL_BGR 0x08 -#define ST77XX_MADCTL_MH 0x04 - -#define TFT_CASET ST7735_CASET -#define TFT_PASET ST7735_RASET -#define TFT_RAMWR ST7735_RAMWR -#define TFT_MADCTL ST7735_MADCTL - -#endif - - - -#ifdef __cplusplus - -class TFT_T_DMA -{ - public: - TFT_T_DMA(uint8_t _CS, uint8_t _DC, uint8_t _RST = 255, uint8_t _MOSI=11, uint8_t _SCLK=13, uint8_t _MISO=12, uint8_t touch_cs=38, uint8_t touch_irq=37); - - void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); - void begin(void); - void flipscreen(bool flip); - boolean isflipped(void); - void startDMA(void); - void stopDMA(); - int get_frame_buffer_size(int *width, int *height); - - // Touch screen functions - #define TOUCH_ENABLED() ((_touch_cs != 255) && (_touch_irq != 255)) - bool isTouching(void) { return ((!TOUCH_ENABLED())?false:(digitalRead(_touch_irq) == LOW)); } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax); - - // NoDMA functions - void writeScreenNoDma(const uint16_t *pcolors); - void fillScreenNoDma(uint16_t color); - void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - // DMA functions - uint16_t * getLineBuffer(int j); - void writeScreen(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int y, uint16_t *buf); - void fillScreen(uint16_t color); - void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - protected: - uint8_t _rst, _cs, _dc; - uint8_t _miso, _mosi, _sclk; - uint8_t _touch_irq=255, _touch_cs=255; - bool flipped=false; - - void wait(void); - void enableTouchIrq(); -}; - -#endif -#endif diff --git a/MCUME_teensy41/teensyo2em/tft_t_dma_config.h b/MCUME_teensy41/teensyo2em/tft_t_dma_config.h deleted file mode 100644 index 0a712da..0000000 --- a/MCUME_teensy41/teensyo2em/tft_t_dma_config.h +++ /dev/null @@ -1,13 +0,0 @@ -#include "platform_config.h" - -//#define ST7789 1 -//#define ILI9341 1 - -#define TFT_LINEARINT 1 -#define LINEARINT_HACK 1 - -//#define FLIP_SCREEN 1 -//#define TFT_DEBUG 1 -#if defined(__IMXRT1052__) || defined(__IMXRT1062__) -//#define TFT_STATICFB 1 -#endif diff --git a/MCUME_teensy41/teensyo2em/vga_t_dma.h b/MCUME_teensy41/teensyo2em/vga_t_dma.h deleted file mode 100644 index 81a986b..0000000 --- a/MCUME_teensy41/teensyo2em/vga_t_dma.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - Wrapping class to extend VGA_T4 to TFT_T_DMA -*/ - -#ifndef _VGA_T_DMAH_ -#define _VGA_T_DMAH_ - -#ifdef __cplusplus -#include -#endif - - -#define RGBVAL16(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) - - - - -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 - -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - - - -#ifdef __cplusplus - -class TFT_T_DMA: public VGA_T4 -{ - public: - // Fake touch screen functions - bool isTouching(void) { return false; } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { } - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { }; - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { } - - // fake DMA functions - void startDMA(void) { }; - void stopDMA(void) { }; - - // fake no DMA functions - void writeScreenNoDma(const vga_pixel *pcolors) { writeScreen(pcolors); } - void fillScreenNoDma(vga_pixel color) { clear(color); } - void drawTextNoDma(int16_t x, int16_t y, const char * text, vga_pixel fgcolor, vga_pixel bgcolor, bool doublesize) { drawText(x,y,text,fgcolor,bgcolor,doublesize); } - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, vga_pixel color) { drawRect(x, y, w, h, color); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap) { drawSprite(x, y, bitmap); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh) { drawSprite(x, y, bitmap, croparx, cropary, croparw, croparh); } -}; - - -#endif -#endif diff --git a/MCUME_teensy41/teensyo2em/vmachine.c b/MCUME_teensy41/teensyo2em/vmachine.c index 96e12fa..094bd42 100644 --- a/MCUME_teensy41/teensyo2em/vmachine.c +++ b/MCUME_teensy41/teensyo2em/vmachine.c @@ -488,11 +488,11 @@ Byte in_bus(void){ switch(mode) { case 1: - if (key & MASK_JOY2_RIGHT) d &= 0xF7; - if (key & MASK_JOY2_LEFT) d &= 0xFD; - if (key & MASK_JOY2_UP) d &= 0xFE; - if (key & MASK_JOY2_DOWN) d &= 0xFB; - if (key & MASK_JOY2_BTN) d &= 0xEF; + if ( (key & MASK_JOY2_LEFT) || (key & MASK_JOY1_LEFT) ) d &= 0xF7; + if ( (key & MASK_JOY2_RIGHT) || (key & MASK_JOY1_RIGHT) ) d &= 0xFD; + if ( (key & MASK_JOY2_UP) || (key & MASK_JOY1_UP) ) d &= 0xFE; + if ( (key & MASK_JOY2_DOWN) || (key & MASK_JOY1_DOWN) ) d &= 0xFB; + if ( (key & MASK_JOY2_BTN) || (key & MASK_JOY1_BTN) ) d &= 0xEF; break; case 2: diff --git a/MCUME_teensy41/teensyo2em/Oddemu.c b/MCUME_teensy41/teensyo2em/wrapemu.c similarity index 98% rename from MCUME_teensy41/teensyo2em/Oddemu.c rename to MCUME_teensy41/teensyo2em/wrapemu.c index ad5fa02..48a4476 100644 --- a/MCUME_teensy41/teensyo2em/Oddemu.c +++ b/MCUME_teensy41/teensyo2em/wrapemu.c @@ -7,7 +7,7 @@ ****************************************************************************/ #include "vmachine.h" #include "vdc.h" -#include "oddemu.h" +#include "wrapemu.h" #include "emuapi.h" @@ -197,6 +197,6 @@ void odd_Step(void) run(); //emu_printf("s"); - emu_DrawScreen((unsigned char *)getGBuf()+BORDERW/2, BMPW-BORDERW, BMPH, BMPW); + emu_DrawScreenPal16((unsigned char *)getGBuf()+BORDERW/2, BMPW-BORDERW, BMPH, BMPW); emu_DrawVsync(); } diff --git a/MCUME_teensy41/teensyo2em/Oddemu.h b/MCUME_teensy41/teensyo2em/wrapemu.h similarity index 100% rename from MCUME_teensy41/teensyo2em/Oddemu.h rename to MCUME_teensy41/teensyo2em/wrapemu.h diff --git a/MCUME_teensy41/teensypce/emuapi.cpp b/MCUME_teensy41/teensypce/emuapi.cpp index 0e98162..e128cca 100644 --- a/MCUME_teensy41/teensypce/emuapi.cpp +++ b/MCUME_teensy41/teensypce/emuapi.cpp @@ -5,25 +5,31 @@ extern "C" { #include "iopins.h" } -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#else -#include "tft_t_dma.h" -#endif +#include -#ifdef HAS_USBKEY +#ifdef HAS_USB #include "USBHost_t36.h" // Read this header first for key info USBHost myusb; USBHub hub1(myusb); +#ifdef HAS_USBKEY KeyboardController keyboard1(myusb); USBHIDParser hid1(myusb); MouseController mouse1(myusb); +#endif +#ifdef HAS_USBMIDI MIDIDevice midi1(myusb); #endif +#ifdef HAS_USBJOY +#define COUNT_JOYSTICKS 4 +JoystickController joysticks[COUNT_JOYSTICKS](myusb); +#endif +#endif static bool emu_writeConfig(void); static bool emu_readConfig(void); static bool emu_eraseConfig(void); +static bool emu_writeGfxConfig(char * display_type); +static int emu_readGfxConfig(void); static bool mouseDetected = false; static bool keyboardDetected = false; @@ -34,6 +40,7 @@ static File file; #define MAX_FILES 64 #define AUTORUN_FILENAME "autorun.txt" +#define GFX_CFG_FILENAME "gfxmode.txt" #define MAX_FILENAME_SIZE 34 #define MAX_MENULINES 9 @@ -53,7 +60,8 @@ static File file; #define MENU_VGA_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) #define MENU_VGA_YOFFSET (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37) -extern TFT_T_DMA tft; +#include "t4_dsp.h" +T4_DSP tft; static int nbFiles=0; static int curFile=0; @@ -65,6 +73,8 @@ static char selected_filename[MAX_FILENAME_SIZE]=""; static char second_selected_filename[MAX_FILENAME_SIZE]=""; static bool menuRedraw=true; static bool autorun=false; +static bool vgahires=false; + static const unsigned short * keys; #ifdef TEECOMPUTER @@ -158,6 +168,29 @@ void emu_Free(void * pt) free(pt); } +#define SMEMPOOL (0x800000) +EXTMEM static unsigned char slowmem[SMEMPOOL]; +static int slowmempt = 0; + +void * emu_SMalloc(unsigned int size) +{ + void * mem = (void*)&slowmem[slowmempt]; + slowmempt += size; + + if ( slowmempt > SMEMPOOL ) { + mem = NULL; + emu_printf("failure to allocate slow"); + } + else { + emu_printf("could allocate slow static "); + emu_printf(size); + } + return mem; +} + +void emu_SFree(void * pt) +{ +} /******************************** * Input and keyboard ********************************/ @@ -329,6 +362,12 @@ int emu_ReadKeys(void) #endif if ( row & 0x02 ) retval |= MASK_JOY2_BTN; + +#ifdef EXTPAD + if ( sh_pressed ) retval |= MASK_KEY_USER3; + if ( fn_pressed ) retval |= MASK_KEY_USER1; + digitalWrite(KLED, 0); +#else // Handle LED flash uint32_t time_ms=millis(); if ((time_ms-last_t_ms) > 100) { @@ -412,8 +451,9 @@ int emu_ReadKeys(void) if ( key_fn ) retval |= MASK_KEY_USER2; if ( ( key_fn ) && (keymatrix[4] == 0x10 )) retval |= MASK_KEY_USER1; +#endif - if ( (key_fn) && (key_sh) ) + if ( (fn_pressed) && (sh_pressed) ) #else if ( ((retval & (MASK_KEY_USER1+MASK_KEY_USER2)) == (MASK_KEY_USER1+MASK_KEY_USER2)) || (retval & MASK_KEY_USER4 ) ) @@ -453,8 +493,10 @@ int emu_ReadKeys(void) while (true) { ; } -#endif +#endif } + + emu_GetJoystick(); return (retval); } @@ -607,7 +649,7 @@ int emu_setKeymap(int index) { } int emu_GetMouse(int *x, int *y, int *buts) { -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBKEY) if (mouse1.available()) { *buts = mouse1.getButtons(); *x = mouse1.getMouseX(); @@ -620,7 +662,23 @@ int emu_GetMouse(int *x, int *y, int *buts) { return 0; } -#ifdef HAS_USBKEY +int emu_GetJoystick(void) { +#if defined(HAS_USB) && (HAS_USBJOY) + for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) { + if (joysticks[joystick_index].available()) { + uint64_t axis_mask = joysticks[joystick_index].axisMask(); + uint64_t axis_changed_mask = joysticks[joystick_index].axisChangedMask(); + uint32_t buttons = joysticks[joystick_index].getButtons(); + Serial.printf("Joystick(%d): buttons = %x", joystick_index, buttons); + Serial.println(); + } + } + return 1; +#endif + return 0; +} + +#if defined(HAS_USB) && (HAS_USBKEY) void OnPress(auto key) { keyboardDetected = true; @@ -764,7 +822,7 @@ int emu_KeyboardDetected(void) { return (keyboardDetected?1:0); } -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) static unsigned char midiBuffer[16]; static unsigned char midiLastCmd=0; static int midiDataCnt=0; @@ -772,8 +830,7 @@ static int midiCmdNbParam=0; #endif void emu_MidiOnDataReceived(unsigned char value) { - -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) //Serial.println(value, HEX); //10000000 = 128 = note off //10010000 = 144 = note on @@ -941,6 +998,7 @@ void emu_MidiOnDataReceived(unsigned char value) { /******************************** * Menu file loader UI ********************************/ +#ifdef FILEBROWSER static int readNbFiles(void) { int totalFiles = 0; @@ -970,8 +1028,6 @@ static int readNbFiles(void) { return totalFiles; } - - void backgroundMenu(void) { menuRedraw=true; tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00)); @@ -981,11 +1037,13 @@ void backgroundMenu(void) { int handleMenu(uint16_t bClick) { if (autorun) { + toggleMenu(false); + menuRedraw=false; return (ACTION_RUN1); } int action = ACTION_NONE; - if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) ) { + if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) || ( bClick & MASK_KEY_USER2 ) ) { char newpath[MAX_FILENAME_PATH]; strcpy(newpath, selection); strcat(newpath, "/"); @@ -996,17 +1054,31 @@ int handleMenu(uint16_t bClick) File file = SD.open(selection); if (file.isDirectory()) { curFile = 0; - nbFiles = readNbFiles(); + nbFiles = readNbFiles(); + menuRedraw=true; } - else { - action = ACTION_RUN1; + else + { #ifdef TEECOMPUTER - if (key_extmode) { + if ( (key_extmode) || ( key_sh) ) { emu_writeConfig(); } + if ( tft.getMode() < MODE_VGA_320x240) { + if ( bClick & MASK_KEY_USER2 ) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + } + //emu_SwapJoysticks(0); #endif + toggleMenu(false); + menuRedraw=false; + return (ACTION_RUN1); } - menuRedraw=true; } else if ( bClick & MASK_KEY_USER1 ) { menuRedraw=true; @@ -1015,19 +1087,14 @@ int handleMenu(uint16_t bClick) strcat(second_selection, "/"); strcat(second_selection, second_selected_filename); action = ACTION_RUN2; - } - else if ( bClick & MASK_KEY_USER2 ) { - menuRedraw=true; - //action = ACTION_RUN3; - emu_SwapJoysticks(0); - } + } else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) { if (curFile!=0) { menuRedraw=true; curFile--; } } - else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { + else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { if ((curFile-9)>=0) { menuRedraw=true; curFile -= 9; @@ -1042,7 +1109,7 @@ int handleMenu(uint16_t bClick) menuRedraw=true; } } - else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { + else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { if ((curFile<(nbFiles-9)) && (nbFiles)) { curFile += 9; menuRedraw=true; @@ -1099,12 +1166,12 @@ int handleMenu(uint16_t bClick) return (action); } -bool menuActive(void) +int menuActive(void) { - return (menuOn); + return (menuOn?1:0); } -void toggleMenu(bool on) { +void toggleMenu(int on) { if (on) { menuOn=true; backgroundMenu(); @@ -1122,7 +1189,7 @@ char * menuSecondSelection(void) { return (second_selection); } - +#endif /******************************** * OSKB handling @@ -1140,8 +1207,9 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) char c[4] = {' ',0,' ',0}; const char * cpt = str; int i=0; - int fb_width,fb_height; - tft.get_frame_buffer_size(&fb_width, &fb_height); + int fb_width,fb_height,fbstride; + + fbstride = tft.get_frame_buffer_size(&fb_width, &fb_height); int ypos = (bottom?(fb_height-2*8):0); int line = row + (bottom?2:0); while ((c[1] = *cpt++)) @@ -1150,7 +1218,7 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0); else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff); if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff); - tft.drawTextNoDma(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); + tft.drawText(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); i++; } } @@ -1248,7 +1316,7 @@ int handleOSKB(void) { return retval; } -void toggleOSKB(bool forceon) { +void toggleOSKB(int forceon) { if (forceon) { oskbOn = true; drawOSKB(); @@ -1332,6 +1400,17 @@ int emu_FileRead(void * buf, int size, int handler) #endif } +int emu_FileWrite(void * buf, int size, int handler) +{ +// emu_printf("emu_FileWrite"); +// emu_printi(handler); +#ifdef HCFH + return (file.write(buf, size)); +#else + return (getFileHandler(handler).write(buf, size)); +#endif +} + int emu_FileGetc(int handler) { // emu_printf("FileGetc"); // emu_printi(handler); @@ -1404,6 +1483,9 @@ unsigned int emu_FileSize(const char * filepath) emu_printf(filesize); lofile.close(); } + else { + emu_printf("filesize failed"); + } return(filesize); } @@ -1489,6 +1571,48 @@ static bool emu_eraseConfig(void) SD.remove (ROMSDIR "/" AUTORUN_FILENAME); } +static bool emu_writeGfxConfig(char * display_type) +{ + bool retval = false; + SD.remove ("/" GFX_CFG_FILENAME); + if (strcmp(display_type, "VGA")) { + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(display_type, strlen(display_type)) != strlen(display_type)) { + emu_printf("GFX config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + } + return retval; +} + +#define CFG_VGA 0 +#define CFG_ILI 1 +#define CFG_ST 2 + +static int emu_readGfxConfig(void) +{ + int retval = CFG_VGA; // No file = VGA + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + if (filesize == 2) // "ST" + { + retval = CFG_ST; + } + else if (filesize == 3) // "ILI" + { + retval = CFG_ILI; + } + lofile.close(); + } + return retval; +} + /******************************** * File IO compatibility ********************************/ @@ -1670,62 +1794,249 @@ FRESULT f_mkdir (const char* path) /******************************** - * Initialization + * GFX wrapper ********************************/ -void emu_init(void) +static unsigned short palette16[PALETTE_SIZE]; +static IntervalTimer myTimer; +volatile boolean vbl=true; +volatile boolean vgatimervsync=false; +static void (*vblCallback)(void) = nullptr; +static int skip=0; + +static void vblCount() { + if (vbl) { + vbl = false; + } else { + vbl = true; + } +} + +void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) +{ + if (index= MODE_VGA_320x240 ) { + if (vgatimervsync) { + while (vbl==vb) {}; + } + else { + tft.waitSync(); + } + } + else { + while (vbl==vb) {}; + } + if (vblCallback != nullptr) { + vblCallback(); + } +} + +void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride) +{ + if (skip == 0) { + tft.writeScreenPal(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); + } +} +void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLinePal(width,height,line, VBuf, palette16); + } +} + +void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine(width,height,line, VBuf); + } +} + +void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine8(width,height,line, VBuf, palette16); + } +} + +int emu_IsVga(void) +{ + return (tft.getMode() >= MODE_VGA_320x240?1:0); +} + +int emu_IsVgaHires(void) +{ + return (tft.getMode() >= MODE_VGA_640x240?1:0); +} + +int emu_FrameSkip(void) +{ + return skip; +} + + +/******************************** + * AUDIO wrapper +********************************/ +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +AudioPlaySystem mymixer; + +void emu_sndInit() { + Serial.println("sound init"); + mymixer.begin_audio(256, mymixer.snd_Mixer); + mymixer.start(); +} + +void emu_sndPlaySound(int chan, int volume, int freq) +{ + if (chan < 6) { + mymixer.sound(chan, freq, volume); + } + /* + Serial.print(chan); + Serial.print(":" ); + Serial.print(volume); + Serial.print(":" ); + Serial.println(freq); + */ +} + +void emu_sndPlayBuzz(int size, int val) { + mymixer.buzz(size,val); + //Serial.print((val==1)?1:0); + //Serial.print(":"); + //Serial.println(size); +} +#endif + +/******************************** + * Initialization +********************************/ +void emu_init(int hires) { Serial.begin(115200); + vgahires = hires; -#ifdef HAS_USBKEY +#ifdef HAS_USB myusb.begin(); +#ifdef HAS_USBKEY keyboard1.attachPress(OnPress); keyboard1.attachRelease(OnRelease); #endif +#endif - while (!SD.begin(SD_CS)) +#ifdef FILEBROWSER + if (!SD.begin(SD_CS)) { - Serial.println("SD begin failed, retrying..."); - delay(1000); + Serial.println("No SD card detected"); } strcpy(selection,ROMSDIR); - FileHandlersInit(); - nbFiles = readNbFiles(); - - Serial.print("SD initialized, files found: "); Serial.println(nbFiles); +#endif emu_InitJoysticks(); #ifdef SWAP_JOYSTICK - joySwapped = true; + joySwapped = true; #else - joySwapped = false; + joySwapped = false; #endif -#ifdef TEECOMPUTER -#ifndef HAS_T4_VGA - tft.flipscreen(false); -#endif -#endif int keypressed = emu_ReadKeys(); +#ifdef HAS_T4_VGA + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } +#else + int gfx_mode = CFG_VGA; // default +#ifdef FILEBROWSER + gfx_mode = emu_readGfxConfig(); +#endif + // Force VGA if UP pressed + if (keypressed & MASK_JOY2_UP) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("VGA"); +#endif + gfx_mode = CFG_VGA; + } + else { + if (keypressed & MASK_JOY2_LEFT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ST"); +#endif + gfx_mode = CFG_ST; + } + else if (keypressed & MASK_JOY2_RIGHT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ILI"); +#endif + gfx_mode = CFG_ILI; + } + } + if (gfx_mode == CFG_VGA) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + else + { + tft.begin(gfx_mode == CFG_ILI?MODE_TFTILI_320x240:MODE_TFTST_320x240); + } +#endif + if (keypressed & MASK_JOY2_DOWN) { tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) ); tft.drawTextNoDma(64,48, (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); +#ifdef FILEBROWSER emu_eraseConfig(); delay(1000); +#endif } else { +#ifdef FILEBROWSER if (emu_readConfig()) { autorun = true; } +#endif } +#ifdef FILEBROWSER toggleMenu(true); +#endif } -void emu_start(void) +void emu_start(int vblms, void * callback, int forcetimervsync) { + vgatimervsync = forcetimervsync?true:false; + tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); + tft.startRefresh(); + if (callback != nullptr) { + vblCallback = callback; + } + + myTimer.begin(vblCount, vblms); +#ifdef HAS_SND + emu_sndInit(); +#endif usbnavpad = 0; } diff --git a/MCUME_teensy41/teensypce/emuapi.h b/MCUME_teensy41/teensypce/emuapi.h index 47ab583..5dd6130 100644 --- a/MCUME_teensy41/teensypce/emuapi.h +++ b/MCUME_teensy41/teensypce/emuapi.h @@ -2,126 +2,14 @@ #define EMUAPI_H #include "platform_config.h" - -#define CUSTOM_SND 1 -//#define TIMER_REND 1 - -#define EXTRA_HEAP 0x10 - -// Title: < > -#define TITLE " PC Engine Emulator" -#define ROMSDIR "/pce" - -#define emu_Init(ROM) {pce_Init(); pce_Start(ROM);} -#define emu_Step(x) {pce_Step();} -#define emu_Input(x) {pce_Input(x);} - -#define MAX_FILENAME_PATH 64 -#define NB_FILE_HANDLER 4 -#define PALETTE_SIZE 1 -#define VID_FRAME_SKIP 0x0 -#define TFT_VBUFFER_YCROP 0 -#define SINGLELINE_RENDERING 1 - -#define R32(rgb) ((rgb>>16)&0xff) -#define G32(rgb) ((rgb>>8)&0xff) -#define B32(rgb) (rgb & 0xff) +#include "emucfg.h" #define ACTION_NONE 0 -#define ACTION_MAXKBDVAL 16 -#define ACTION_EXITKBD 128 -#define ACTION_RUN1 129 -#define ACTION_RUN2 130 -#define ACTION_RUN3 131 - -#ifdef KEYMAP_PRESENT - -#define keylables_map0_0 (char *)"qwertyuiop\x1a" -#define keylables_map0_1 (char *)" asdfghjkl\x19" -#define keylables_map0_2 (char *)" zxcvbnm,.;/" -#define keylables_map0_3 (char *)" +\x10-" -const unsigned short key_map0[] = { - 'q','w','e','r','t','y','u','i','o','p',157, //lowecase - 0,'a','s','d','f','g','h','j','k','l',0x0D, - 0,'z','x','c','v','b','n','m',',','.',';','/', - 145,157,29,17, - 0,'+',' ','-' - }; - -#define keylables_map1_0 (char *)"QWERTYUIOP@" -#define keylables_map1_1 (char *)" ASDFGHJKL\x19" -#define keylables_map1_2 (char *)" ZXCVBNM<>:?" -#define keylables_map1_3 (char *)" =\x10_" -const unsigned short key_map1[] = { - 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase - 0,'A','S','D','F','G','H','J','K','L',0x0D, - 0,'Z','X','C','V','B','N','M','<','>',':','?', - 145,157,29,17, - 0,'=',' ','_' - }; - -#define keylables_map2_0 (char *)"!\"#$%^&*()@" -#define keylables_map2_1 (char *)" |\\[]{} " -#define keylables_map2_2 (char *)" <>:?" -#define keylables_map2_3 (char *)" =\x10_" -const unsigned short key_map2[] = { - '!','"','#','$','%','^','&','*','(',')','@', // shiftothers - 0, '|','\\','[',']','{','}','\'',0,0,0, - 0, 0,0,0,0,0,0,0,'<','>',':','?', - 0,0,0,0, - 0,'=',' ','_' - }; - -#define keylables_map3_0 (char *)"1234567890 " -#define keylables_map3_1 (char *)" " -#define keylables_map3_2 (char *)" " -#define keylables_map3_3 (char *)" " - -const unsigned short key_map3[] = { - '1','2','3','4','5','6','7','8','9','0',0, // digit keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map4_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " -#define keylables_map4_1 (char *)" " -#define keylables_map4_2 (char *)" " -#define keylables_map4_3 (char *)" " - -const unsigned short key_map4[] = { - 133,134,135,136,137,138,139,140,0,0,0, // function keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map5_0 (char *)" " -#define keylables_map5_1 (char *)" " -#define keylables_map5_2 (char *)" " -#define keylables_map5_3 (char *)" " - -const unsigned short key_map5[] = { - 0,0,0,0,0,0,0,0,0,0,0, // extra keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -const unsigned short matkeys[] = { - 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 - 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 - 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 - 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN - 0x510,0x010,0x110,0x310, // row 4 - }; - -#endif - +#define ACTION_RUN1 1 +#define ACTION_RUN2 2 +#define FORCE_VGATIMERVSYNC 1 +#define SUPPORT_HIRES 1 #define MASK_JOY2_RIGHT 0x0001 #define MASK_JOY2_LEFT 0x0002 @@ -138,24 +26,25 @@ const unsigned short matkeys[] = { #define MASK_JOY1_BTN 0x1000 #define MASK_KEY_USER4 0x2000 +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) #ifdef __cplusplus extern "C" { -#else -#define bool unsigned char +extern void emu_init(int hires=0); +extern void emu_start(int vblms, void * callback, int forcetimervsync=0); #endif - -extern void emu_init(void); -extern void emu_start(void); extern void emu_printf(const char * text); extern void emu_printi(int val); extern void emu_printh(int val); extern void * emu_Malloc(unsigned int size); extern void * emu_MallocI(unsigned int size); extern void emu_Free(void * pt); +extern void * emu_SMalloc(unsigned int size); +extern void emu_SFree(void * pt); extern int emu_FileOpen(const char * filepath, const char * mode); extern int emu_FileRead(void * buf, int size, int handler); +extern int emu_FileWrite(void * buf, int size, int handler); extern int emu_FileGetc(int handler); extern int emu_FileSeek(int handler, int seek, int origin); extern int emu_FileTell(int handler); @@ -166,24 +55,23 @@ extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size); extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek); extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index); -extern void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride); -extern void emu_DrawLine(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line); extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line); +extern void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride); extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line); -extern void emu_CopyLine(int width, int height, int ysrc, int ydst); extern void emu_DrawVsync(void); extern int emu_FrameSkip(void); -extern void * emu_LineBuffer(int line); -extern void emu_tweakVideo(int shiftdelta, int numdelta, int denomdelta); +extern int emu_IsVga(void); +extern int emu_IsVgaHires(void); -extern bool menuActive(void); +extern int menuActive(void); extern char * menuSelection(void); extern char * menuSecondSelection(void); -extern void toggleMenu(bool on); +extern void toggleMenu(int on); extern int handleMenu(unsigned short bClick); extern int handleOSKB(void); -extern void toggleOSKB(bool forceon); +extern void toggleOSKB(int forceon); extern void emu_InitJoysticks(void); extern int emu_SwapJoysticks(int statusOnly); @@ -192,6 +80,7 @@ extern int emu_ReadKeys(void); extern int emu_GetPad(void); extern int emu_GetMouse(int *x, int *y, int *buts); extern int emu_MouseDetected(void); +extern int emu_GetJoystick(void); extern int emu_KeyboardDetected(void); extern int emu_ReadAnalogJoyX(int min, int max); extern int emu_ReadAnalogJoyY(int min, int max); diff --git a/MCUME_teensy41/teensypce/emucfg.h b/MCUME_teensy41/teensypce/emucfg.h new file mode 100644 index 0000000..100bdaa --- /dev/null +++ b/MCUME_teensy41/teensypce/emucfg.h @@ -0,0 +1,115 @@ +#ifndef EMUCFG_H +#define EMUCFG_H + +#include "wrapemu.h" + +// Title: < > +#define TITLE " PC Engine Emulator" +#define ROMSDIR "/pce" + +#define emu_Init(ROM) {pce_Init(); pce_Start(ROM);} +#define emu_Step(x) {pce_Step();} +#define emu_Input(x) {pce_Input(x);} + +#define MAX_FILENAME_PATH 64 +#define NB_FILE_HANDLER 4 + +#define PALETTE_SIZE 1 +#define VID_FRAME_SKIP 0x0 +#define TFT_VBUFFER_YCROP 0 +#define SINGLELINE_RENDERING 1 +#define CUSTOM_SND 1 +//#define TIMER_REND 1 +//#define EXTPAD 1 +#define EXTRA_HEAP 0x10 +#define FILEBROWSER 1 + + +#ifdef KEYMAP_PRESENT + +#define keylables_map0_0 (char *)"qwertyuiop\x1a" +#define keylables_map0_1 (char *)" asdfghjkl\x19" +#define keylables_map0_2 (char *)" zxcvbnm,.;/" +#define keylables_map0_3 (char *)" +\x10-" +const unsigned short key_map0[] = { + 'q','w','e','r','t','y','u','i','o','p',157, //lowecase + 0,'a','s','d','f','g','h','j','k','l',0x0D, + 0,'z','x','c','v','b','n','m',',','.',';','/', + 145,157,29,17, + 0,'+',' ','-' + }; + +#define keylables_map1_0 (char *)"QWERTYUIOP@" +#define keylables_map1_1 (char *)" ASDFGHJKL\x19" +#define keylables_map1_2 (char *)" ZXCVBNM<>:?" +#define keylables_map1_3 (char *)" =\x10_" +const unsigned short key_map1[] = { + 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase + 0,'A','S','D','F','G','H','J','K','L',0x0D, + 0,'Z','X','C','V','B','N','M','<','>',':','?', + 145,157,29,17, + 0,'=',' ','_' + }; + +#define keylables_map2_0 (char *)"!\"#$%^&*()@" +#define keylables_map2_1 (char *)" |\\[]{} " +#define keylables_map2_2 (char *)" <>:?" +#define keylables_map2_3 (char *)" =\x10_" +const unsigned short key_map2[] = { + '!','"','#','$','%','^','&','*','(',')','@', // shiftothers + 0, '|','\\','[',']','{','}','\'',0,0,0, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 0,0,0,0, + 0,'=',' ','_' + }; + +#define keylables_map3_0 (char *)"1234567890 " +#define keylables_map3_1 (char *)" " +#define keylables_map3_2 (char *)" " +#define keylables_map3_3 (char *)" " + +const unsigned short key_map3[] = { + '1','2','3','4','5','6','7','8','9','0',0, // digit keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map4_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " +#define keylables_map4_1 (char *)" " +#define keylables_map4_2 (char *)" " +#define keylables_map4_3 (char *)" " + +const unsigned short key_map4[] = { + 133,134,135,136,137,138,139,140,0,0,0, // function keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map5_0 (char *)" " +#define keylables_map5_1 (char *)" " +#define keylables_map5_2 (char *)" " +#define keylables_map5_3 (char *)" " + +const unsigned short key_map5[] = { + 0,0,0,0,0,0,0,0,0,0,0, // extra keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +const unsigned short matkeys[] = { + 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 + 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 + 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 + 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN + 0x510,0x010,0x110,0x310, // row 4 + }; + +#endif + +#endif diff --git a/MCUME_teensy41/teensypce/platform_config.h b/MCUME_teensy41/teensypce/platform_config.h index 3464dc2..914d152 100644 --- a/MCUME_teensy41/teensypce/platform_config.h +++ b/MCUME_teensy41/teensypce/platform_config.h @@ -4,13 +4,13 @@ #define TEECOMPUTER 1 #ifdef TEECOMPUTER -//#define ILI9341 1 -//#define ST7789 1 -//#define TFTSPI1 1 -#define HAS_T4_VGA 1 +#define TFTSPI1 1 +//#define HAS_T4_VGA 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 -//#define INVX 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 #define PT8211 1 #else @@ -19,7 +19,11 @@ //#define INVX 1 #define INVY 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 +#define PT8211 1 #endif diff --git a/MCUME_teensy41/teensypce/shared.h b/MCUME_teensy41/teensypce/shared.h index abc2a92..64787dc 100644 --- a/MCUME_teensy41/teensypce/shared.h +++ b/MCUME_teensy41/teensypce/shared.h @@ -4,8 +4,6 @@ #define XOFFSET 0x20 #define LSB_FIRST 1 -#define SOUND_PRESENT 1 - #include "pcetypes.h" #include "h6280.h" diff --git a/MCUME_teensy41/teensypce/system.c b/MCUME_teensy41/teensypce/system.c index dc1162f..7f9a286 100644 --- a/MCUME_teensy41/teensypce/system.c +++ b/MCUME_teensy41/teensypce/system.c @@ -16,6 +16,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "shared.h" +#include "platform_config.h" t_bitmap bitmap; t_input input; @@ -30,13 +31,13 @@ int system_init(int sample_rate) vdc_init(); psg_init(); render_init(); -#ifdef SOUND_PRESENT +#ifdef HAS_SND audio_init(sample_rate); #endif return (1); } -#ifdef SOUND_PRESENT +#ifdef HAS_SND void audio_init(int rate) { memset(&pcesnd, 0, sizeof(pcesnd)); diff --git a/MCUME_teensy41/teensypce/t4_dsp.cpp b/MCUME_teensy41/teensypce/t4_dsp.cpp new file mode 100644 index 0000000..43301fa --- /dev/null +++ b/MCUME_teensy41/teensypce/t4_dsp.cpp @@ -0,0 +1,1774 @@ +/* + TFT/VGA driver + DMA TFT driver based on C64 ILI9341 dma driver from Frank Bösing, 2017 +*/ + +#include "T4_DSP.h" + +#include +#include + +#include "font8x8.h" + +// TFT constants and variables +#define TFT_LINEARINT 1 +#define LINEARINT_HACK 1 +#define DMA_LINES_PER_BLOCK 64 +#define DMA_NUM_SETTINGS 4 + +#define TFT_SWRESET 0x01 +#define TFT_SLPOUT 0x11 +#define TFT_INVON 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_MADCTL 0x36 +#define TFT_PIXFMT 0x3A +#define TFT_MADCTL_MY 0x80 +#define TFT_MADCTL_MX 0x40 +#define TFT_MADCTL_MV 0x20 +#define TFT_MADCTL_ML 0x10 +#define TFT_MADCTL_RGB 0x00 +#define TFT_MADCTL_BGR 0x08 +#define TFT_MADCTL_MH 0x04 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) +//#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) +//#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) +//#define R16(rgb) ((rgb>>8)&0xf8) +//#define G16(rgb) ((rgb>>3)&0xfc) +//#define B16(rgb) ((rgb<<3)&0xf8) + +// LPSPI4 = SPI0 in Teensy 4.0 +// LPSPI3 = SPI1 in Teensy 4.0 +// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) + +#ifdef TFTSPI1 +#define SPI SPI1 +#define LPSPIP_TDR LPSPI3_TDR +#define LPSPIP_CR LPSPI3_CR +#define LPSPIP_CFGR1 LPSPI3_CFGR1 +#define LPSPIP_TCR LPSPI3_TCR +#define LPSPIP_DER LPSPI3_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX +#else +#define LPSPIP_TDR LPSPI4_TDR +#define LPSPIP_CR LPSPI4_CR +#define LPSPIP_CFGR1 LPSPI4_CFGR1 +#define LPSPIP_TCR LPSPI4_TCR +#define LPSPIP_DER LPSPI4_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX +#endif + +#define SPICLOCK 60000000 +#define SPI_MODE SPI_MODE0 + +// VGA constants and macros +typedef uint8_t vga_pixel; +#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) + +static DMASetting dmasettings[DMA_NUM_SETTINGS]; +static DMAChannel dmatx; +static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K +static volatile uint8_t rstop = 0; +static volatile bool cancelled = false; +static volatile uint8_t curTransfer = 0; +static uint8_t nbTransfer = 0; +static uint16_t * tft_buffer; +static int tft_width; +static int tft_height; +static int tft_stride; + +#define DELAY_MASK 0x80 +PROGMEM static const uint8_t init_commands[] = { + 1+DELAY_MASK, TFT_SWRESET, 150, + 1+DELAY_MASK, TFT_SLPOUT, 255, + 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, + 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, + 1, TFT_INVON, + 1, TFT_DISPON, + 0 +}; + +// VGA constants and variables +// Objective: +// generates VGA signal fully in hardware with as little as possible CPU help + +// Principle: +// QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) +// 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate +// RGB out, combined to create 8bits(/12bits) output. + +// Note: +// - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels +// - experimental resolution: 352x240,352x480 +// - experimental resolution: 512x240,512x480 (not stable) +// - video memory is allocated using malloc in T4 heap +// - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing +// but tried to be compensated by pixel shifting +// - Default is 8bits RRRGGGBB (332) +// But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! +// - Only ok at 600MHz else some disturbances visible + + + +#define TOP_BORDER 40 +#define PIN_HBLANK 15 + +#define PIN_R_B2 33 +#define PIN_R_B1 4 +#define PIN_R_B0 3 +#define PIN_G_B2 2 +#define PIN_G_B1 13 +#define PIN_G_B0 11 +#define PIN_B_B1 12 +#define PIN_B_B0 10 + + +#define DMA_HACK 0x80 + +#define R16(rgb) ((rgb>>8)&0xf8) +#define G16(rgb) ((rgb>>3)&0xfc) +#define B16(rgb) ((rgb<<3)&0xf8) + +// VGA 640x480@60Hz +// Screen refresh rate 60 Hz +// Vertical refresh 31.46875 kHz +// Pixel freq. 25.175 MHz +// +// Visible area 640 25.422045680238 us +// Front porch 16 0.63555114200596 us +// Sync pulse 96 3.8133068520357 us +// Back porch 48 1.9066534260179 us +// Whole line 800 31.777557100298 us + +#define frame_freq 60.0 // Hz +#define line_freq 31.46875 // KHz +#define pix_freq (line_freq*800) // KHz (25.175 MHz) + +// pix_period = 39.7ns +// H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) +#define frontporch_pix 20 //16 +#define backporch_pix 44 //48 + +// Flexio Clock +// PLL3 SW CLOCK (3) => 480 MHz +// PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) +#define FLEXIO_CLK_SEL_PLL3 3 +#define FLEXIO_CLK_SEL_PLL5 2 + +/* Set video PLL */ +// There are /1, /2, /4, /8, /16 post dividers for the Video PLL. +// The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, +// and CCM_ANALOG_MISC2 register sets according to the following equation. +// PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + +// nfact: +// This field controls the PLL loop divider. +// Valid range for DIV_SELECT divider value: 27~54. + +#define POST_DIV_SELECT 2 + +// Full buffer including back/front porch +static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; +static uint32_t dstbuffer __attribute__((aligned(32))); + +// Visible vuffer +static vga_pixel * vga_buffer; +static int vga_width; +static int vga_height; +static int vga_stride; + +static int maxpixperline; +static int left_border; +static int right_border; +static int line_double; +static int pix_shift; +static int ref_div_select; +static int ref_freq_num; +static int ref_freq_denom; +static int ref_pix_shift; +static int combine_shiftreg; + +#ifdef DEBUG +static uint32_t ISRTicks_prev = 0; +volatile uint32_t ISRTicks = 0; +#endif + +uint8_t T4_DSP::_rst; +uint8_t T4_DSP::_cs; +uint8_t T4_DSP::_dc; +uint8_t T4_DSP::_mosi; +uint8_t T4_DSP::_sclk; +uint8_t T4_DSP::_vsync_pin = -1; +DMAChannel T4_DSP::flexio1DMA; +DMAChannel T4_DSP::flexio2DMA; + +static volatile uint32_t VSYNC = 0; +static volatile uint32_t currentLine=0; +#define NOP asm volatile("nop\n\t"); +static gfx_mode_t gfxmode = MODE_UNDEFINED; + + +FASTRUN void T4_DSP::TFT_isr(void) { + dmatx.clearInterrupt(); + curTransfer++; + if (curTransfer >= nbTransfer) { + curTransfer = 0; + if (cancelled) { + dmatx.disable(); + rstop = 1; + } + } + arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); +} + +FASTRUN void T4_DSP::QT3_isr(void) { + TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); + TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); + + cli(); + + // V-PULSE + if (currentLine > 0) { + digitalWrite(_vsync_pin, 1); + VSYNC = 0; + } else { + digitalWrite(_vsync_pin, 0); + VSYNC = 1; + } + + currentLine++; + currentLine = currentLine % 525; + + + uint32_t y = (currentLine - TOP_BORDER) >> line_double; + // Visible area + + if (y >= 0 && y < vga_height) { + // Disable DMAs + //DMA_CERQ = flexio2DMA.channel; + //DMA_CERQ = flexio1DMA.channel; + + // Setup source adress + // Aligned 32 bits copy + unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; + flexio2DMA.TCD->SADDR = p; + if (pix_shift & DMA_HACK) + { + // Unaligned copy + uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; + flexio1DMA.TCD->SADDR = p2; + } + else { + p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 + flexio1DMA.TCD->SADDR = p; + } + + // Enable DMAs + //flexio2DMA.enable(); + //flexio1DMA.enable(); + DMA_SERQ = flexio2DMA.channel; + DMA_SERQ = flexio1DMA.channel; + arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); + } + sei(); + +#ifdef DEBUG + ISRTicks++; +#endif + asm volatile("dsb"); +} + +static void setDmaStruct() { + uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; + uint16_t * fb = (uint16_t*)malloc(remaining); + tft_buffer = fb; + tft_width = TFT_WIDTH; + tft_height = TFT_HEIGHT; + tft_stride = TFT_WIDTH; + uint16_t col=RGBVAL16(0x00,0x00,0x00); + int i=0; + while (remaining > 0) { + int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); + blocks[i] = fb; + for (int j=0;jATTR_DST = 1; + dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); + dmasettings[i].interruptAtCompletion(); + fb += len/2; + remaining -= len; + i++; + } + dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); + nbTransfer = i; +} + +static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 +{ +//if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; + CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE + | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 + | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); + CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; + CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock + const int div_post_pll = 1; // other values: 2,4 + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass +} + +T4_DSP::T4_DSP() +{ + _cs = TFT_CS; + _dc = TFT_DC; + _rst = TFT_RST; + _mosi = TFT_MOSI; + _sclk = TFT_SCLK; + pinMode(_dc, OUTPUT); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, 1); + digitalWrite(_dc, 1); + _vsync_pin = 8; +} + + +void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { + int dx=0; + int dy=0; + digitalWrite(_dc, 0); + SPI.transfer(TFT_CASET); + digitalWrite(_dc, 1); + SPI.transfer16(x1+dx); + digitalWrite(_dc, 1); + SPI.transfer16(x2+dx); + digitalWrite(_dc, 0); + SPI.transfer(TFT_PASET); + digitalWrite(_dc, 1); + SPI.transfer16(y1+dy); + digitalWrite(_dc, 1); + SPI.transfer16(y2+dy); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + return; +} + +void T4_DSP::tft_setup(bool isST) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + // RESET if reset pin defined + if (_rst != 0xff) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + const uint8_t *addr = init_commands; + uint8_t count; + digitalWrite(_cs, 0); + while (count = *addr++) { + uint8_t command = *addr++; + if ( (command == TFT_INVON) && (!isST) ) { + // Skip TFT_INVON for ILI + } + else { + digitalWrite(_dc, 0); // command + SPI.transfer(command); + uint16_t ms = count & DELAY_MASK; + count &= ~DELAY_MASK; + while (--count > 0) { // data + uint8_t data = *addr++; + if ( (command == TFT_MADCTL) && (isST) ) { + data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; + } + digitalWrite(_dc, 1); + SPI.transfer(data); + } + if (ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + digitalWrite(_cs, 1); + SPI.endTransaction(); + delay(2); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + } + } + } + digitalWrite(_cs, 1); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + SPI.endTransaction(); + /* + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_dc, 0); + digitalWrite(_cs, 0); + SPI.transfer(TFT_MADCTL); + digitalWrite(_dc, 1); + SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); + // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); + digitalWrite(_cs, 1); + SPI.endTransaction(); + */ + cancelled = false; +} + +// display VGA image +gfx_error_t T4_DSP::begin(gfx_mode_t mode) +{ + uint32_t flexio_clock_div; + combine_shiftreg = 0; +// int div_select = 49; +// int num = 135; +// int denom = 100; + int div_select = 20; + int num = 9800; + int denom = 10000; + int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; + int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; + set_videoClock(div_select,num,denom,true); + +#ifdef DEBUG + Serial.println(mode); + Serial.println("mode"); +#endif + + switch(mode) + { + case MODE_TFTILI_320x240: +#ifdef DEBUG + Serial.println("TFTILI_320x240"); +#endif + tft_setup(false); + gfxmode = mode; + break; + case MODE_TFTST_320x240: +#ifdef DEBUG + Serial.println("TFTST_320x240"); +#endif + tft_setup(true); + gfxmode = mode; + break; + + case MODE_VGA_320x240: +#ifdef DEBUG + Serial.println("VGA_320x240"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_320x480: +#ifdef DEBUG + Serial.println("VGA_320x480"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_640x240: +#ifdef DEBUG + Serial.println("VGA_640x240"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/pix_freq; + line_double = 1; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_640x480: +#ifdef DEBUG + Serial.println("VGA_640x480"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = (flexio_freq/pix_freq); + line_double = 0; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_512x240: +#ifdef DEBUG + Serial.println("VGA_512x240"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 1; + pix_shift = 0; + break; + + case MODE_VGA_512x480: +#ifdef DEBUG + Serial.println("VGA_512x480"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 0; + pix_shift = 0; + break; + + case MODE_VGA_352x240: +#ifdef DEBUG + Serial.println("VGA_352x240"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_352x480: +#ifdef DEBUG + Serial.println("VGA_352x480"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + } + + if (mode >= MODE_VGA_320x240) + { + if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { + fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); + digitalWrite(_cs, 0); + digitalWrite(_dc, 0); + SPI.transfer(TFT_DISPOFF); + digitalWrite(_cs, 1); + delay(20); + digitalWrite(_cs, 0); + digitalWrite(_cs, 1); + } + gfxmode = mode; + + maxpixperline = vga_stride; + // Save param for tweek adjustment + ref_div_select = div_select; + ref_freq_num = num; + ref_freq_denom = denom; + ref_pix_shift = pix_shift; + +#ifdef DEBUG + Serial.println("frequency"); + Serial.println(flexio_freq); + Serial.println("div"); + Serial.println(flexio_freq/pix_freq); +#endif + + pinMode(_vsync_pin, OUTPUT); + pinMode(PIN_HBLANK, OUTPUT); + + /* Basic pin setup FlexIO1 */ + pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 + pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 + pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 + pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 + /* Basic pin setup FlexIO2 */ + pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 + pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 + pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 + pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 + + /* High speed and drive strength configuration */ + *(portControlRegister(PIN_G_B2)) = 0xFF; + *(portControlRegister(PIN_R_B0)) = 0xFF; + *(portControlRegister(PIN_R_B1)) = 0xFF; + *(portControlRegister(PIN_R_B2)) = 0xFF; + *(portControlRegister(PIN_B_B0)) = 0xFF; + *(portControlRegister(PIN_B_B1)) = 0xFF; + *(portControlRegister(PIN_G_B0)) = 0xFF; + *(portControlRegister(PIN_G_B1)) = 0xFF; + + /* Set clock for FlexIO1 and FlexIO2 */ + CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) + | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); + CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) + | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); + + + /* Set up pin mux FlexIO1 */ + *(portConfigRegister(PIN_G_B2)) = 0x14; + *(portConfigRegister(PIN_R_B0)) = 0x14; + *(portConfigRegister(PIN_R_B1)) = 0x14; + *(portConfigRegister(PIN_R_B2)) = 0x14; + /* Set up pin mux FlexIO2 */ + *(portConfigRegister(PIN_B_B0)) = 0x14; + *(portConfigRegister(PIN_B_B1)) = 0x14; + *(portConfigRegister(PIN_G_B0)) = 0x14; + *(portConfigRegister(PIN_G_B1)) = 0x14; + + /* Enable the clock */ + CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + /* Enable the FlexIO with fast access */ + FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + + uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; + uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; + + /* Shifter 0 registers for FlexIO2 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 + inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter + stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled + startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable + timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 + timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock + pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output + pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity + shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode + /* Shifter 0 registers for FlexIO1 */ + FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + /* Shifter 0 registers for FlexIO1 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 + FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + if (combine_shiftreg) { + pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled + FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + } + /* Timer 0 registers for FlexIO2 */ + timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset + timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output + timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset + timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare + timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert + stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled + startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled + if (combine_shiftreg) { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag + } + else { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag + } + triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low + triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected + pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled + //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 + //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high + timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode + // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) + + int shifts_per_transfer; + if (combine_shiftreg) { + shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 + } + else { + shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 + } + FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); + /* Timer 0 registers for FlexIO1 */ + FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); +#ifdef DEBUG + Serial.println("FlexIO setup complete"); +#endif + + /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ + if (combine_shiftreg) { + FLEXIO2_SHIFTSDEN |= (1<<1); + FLEXIO1_SHIFTSDEN |= (1<<1); + } + else { + FLEXIO2_SHIFTSDEN |= (1<<0); + FLEXIO1_SHIFTSDEN |= (1<<0); + } + /* Disable DMA channel so it doesn't start transferring yet */ + flexio1DMA.disable(); + flexio2DMA.disable(); + /* Set up DMA channel to use Shifter 0 trigger */ + flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); + flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); + + + if (combine_shiftreg) { + flexio2DMA.TCD->NBYTES = 8; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 8; + flexio2DMA.TCD->CITER = maxpixperline / 8; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + flexio1DMA.TCD->NBYTES = 8; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 8; + flexio1DMA.TCD->CITER = maxpixperline / 8; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Setup DMA2 Flexio2 copy + flexio2DMA.TCD->NBYTES = 4; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 4; + flexio2DMA.TCD->CITER = maxpixperline / 4; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + // Setup DMA1 Flexio1 copy + // Use pixel shift to avoid color smearing? + if (pix_shift & DMA_HACK) + { + if (pix_shift & 0x3 == 0) { + // Aligned 32 bits copy (32bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Unaligned (source) 32 bits copy (8bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 1; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion + } + } + else + { + // Aligned 32 bits copy + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + } + +#ifdef DEBUG + Serial.println("DMA setup complete"); +#endif + + // enable clocks for QTIMER3: generates the 15KHz for hsync + // Pulse: + // low : 3.8133 us => 569x6.7ns + // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) + // (OLD TEST) + // (4us low, 28us high => 32us) + // (597x6.7ns for 4us) + // (4179x6.7ns for 28us) + CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 + //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 + + #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz + #define MARGIN_D 1000 + + TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer + // Invert output pin as we want the interupt on rising edge + TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) + TMR3_CNTR3 = 0; + TMR3_LOAD3 = 0; + + /* Inverted timings */ + unsigned long long cpu_freq = F_CPU; + unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; + int rate2 = rate; + + int substract = 1; + if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { + substract=5; + rate2=1652; + } + + #ifdef DEBUG + Serial.print("MARGIN_N is: "); + Serial.println(rate2, DEC); + Serial.print("SUBSTRACT is: "); + Serial.println(substract, DEC); +#endif + TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; + TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; + /* + TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; + */ + TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on + TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), + // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) + //configure Teensy pin Compare output + IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 + attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function + NVIC_ENABLE_IRQ(IRQ_QTIMER3); +#ifdef DEBUG + Serial.println("QTIMER3 setup complete"); + Serial.print("V-PIN is "); + Serial.println(_vsync_pin); +#endif + + /* initialize gfx buffer */ + if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift + if (gfxbuffer == NULL) return(GFX_ERROR); +#ifdef DEBUG + Serial.println("Memory allocated"); +#endif + + memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); + vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; +#ifdef DEBUG + Serial.println(vga_stride); + Serial.println(vga_height); + Serial.println("Screen cleared"); +#endif + } + + return(GFX_OK); +} + +gfx_mode_t T4_DSP::getMode(void) +{ + return gfxmode; +} + +void T4_DSP::startRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + curTransfer = 0; + rstop = 0; + //dmatx.begin(true); + dmatx.attachInterrupt(TFT_isr); + setDmaStruct(); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + + digitalWrite(_cs, HIGH); + SPI.begin(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + + LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: + LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX + LPSPIP_TCR = 15; // Framesize 16 Bits + //LPSPIP_FCR = 0; // Fifo Watermark + LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable + LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: + dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); + + dmatx = dmasettings[0]; + digitalWrite(_cs, 0); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + dmatx.enable(); + } +} + + +void T4_DSP::stopRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + rstop = 1; + unsigned long m = millis(); + cancelled = true; + while (!rstop) { + if ((millis() - m) > 100) break; + delay(10); + asm volatile("wfi"); + }; + rstop = 0; + delay(50); + cancelled = false; + dmatx.detachInterrupt(); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + SPI.end(); +#ifdef ST7789 +// begin(gfxmode); +#endif + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + } +} + +int T4_DSP::get_frame_buffer_size(int *width, int *height) { + if (gfxmode < MODE_VGA_320x240) { + if (width != nullptr) *width = tft_width; + if (height != nullptr) *height = tft_height; + return tft_stride; + } + else { + if (width != nullptr) *width = vga_width; + if (height != nullptr) *height = vga_height; + return vga_stride; + } +} + +void T4_DSP::waitSync() +{ + if (gfxmode >= MODE_VGA_320x240) { + while (VSYNC == 0) {}; + } +} + +void T4_DSP::waitLine(int line) +{ + if (gfxmode >= MODE_VGA_320x240) { + while (currentLine != line) {}; + } +} + +/*********************************************************************************************** + No DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreenNoDma(uint16_t color) { + if (gfxmode < MODE_VGA_320x240) { + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + int i,j; + for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(arx, ary, arx+arw-1, ary+arh-1); + bitmap = bitmap + bmp_offy*w + bmp_offx; + for (int row=0;row> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + bits = *charpt++; + //digitalWrite(_dc, 1); + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + x +=8; + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + else { + drawText(x, y, text, fgcolor, bgcolor, doublesize); + } +} + + +/*********************************************************************************************** + DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreen(uint16_t color) { + int i,j; + if (gfxmode < MODE_VGA_320x240) { + for (j=0; j> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + dst=&tft_buffer[l*tft_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + x +=8; + } + } + else { + vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); + vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); + vga_pixel * dst; + while ((c = *text++)) { + const unsigned char * charpt=&font8x8[c][0]; + int l=y; + for (int i=0;i<8;i++) + { + unsigned char bits; + if (doublesize) { + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + x +=8; + } + } +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { + drawSprite(x,y,bitmap, 0,0,0,0); +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) +{ + int bmp_offx = 0; + int bmp_offy = 0; + uint16_t *bmp_ptr; + int w =*bitmap++; + int h = *bitmap++; + if ( (arw == 0) || (arh == 0) ) { + // no crop window + arx = x; + ary = y; + arw = w; + arh = h; + } + else { + if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + int l=ary; + bitmap = bitmap + bmp_offy*w + bmp_offx; + + if (gfxmode < MODE_VGA_320x240) { + for (int row=0;row tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]; + pos +=step; + } + #endif + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i 2) ) y += (tft_height-height)/2; + uint16_t * dst=&tft_buffer[y*tft_stride]; + if (width > tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]]; + pos +=step; + } +#endif + } + else if ((width*2) == tft_width) { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]]; + *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i tft_width) { + int step = ((width << 8)/tft_width); + int pos = 0; + for (int i=0; i> 8]]; + pos +=step; + } + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = pix; + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i +#include +#endif + +#include "platform_config.h" +#include "iopins.h" + + + +#ifndef TFT_WIDTH +#define TFT_WIDTH 320 +#endif +#define TFT_REALWIDTH 320 + +#ifndef TFT_HEIGHT +#define TFT_HEIGHT 240 +#endif +#define TFT_REALHEIGHT 240 + + +typedef enum gfx_mode_t +{ + MODE_UNDEFINED = 0, + MODE_TFTILI_320x240 = 1, + MODE_TFTST_320x240 = 2, + MODE_VGA_320x240 = 3, + MODE_VGA_320x480 = 4, + MODE_VGA_352x240 = 5, + MODE_VGA_352x480 = 6, + MODE_VGA_512x240 = 7, + MODE_VGA_512x480 = 8, + MODE_VGA_640x240 = 9, + MODE_VGA_640x480 = 10 +} gfx_mode_t; + +typedef enum gfx_error_t +{ + GFX_OK = 0, + GFX_ERROR = -1 +} gfx_error_t; + + +#ifdef __cplusplus + +class T4_DSP +{ + public: + T4_DSP(); + + gfx_error_t begin(gfx_mode_t mode); + gfx_mode_t getMode(void); + void startRefresh(void); + void stopRefresh(); + + int get_frame_buffer_size(int *width, int *height); + void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); + + // wait next Vsync + void waitSync(); + void waitLine(int line); + + // NoDMA functions + void fillScreenNoDma(uint16_t color); + void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + // DMA functions + void fillScreen(uint16_t color); + void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + void writeLine(int width, int height, int y, uint16_t *buf); + void writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + void writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16); + void writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + + protected: + static uint8_t _rst, _cs, _dc; + static uint8_t _mosi, _sclk; + static uint8_t _vsync_pin; + static DMAChannel flexio1DMA; + static DMAChannel flexio2DMA; + void tft_setup(bool isST); + static void TFT_isr(void); + static void QT3_isr(void); +}; + +#endif +#endif diff --git a/MCUME_teensy41/teensypce/teensypce.ino b/MCUME_teensy41/teensypce/teensypce.ino index 85c4870..75d8ed5 100644 --- a/MCUME_teensy41/teensypce/teensypce.ino +++ b/MCUME_teensy41/teensypce/teensypce.ino @@ -3,132 +3,20 @@ extern "C" { #include "emuapi.h" } -#include "emu.h" - -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -TFT_T_DMA tft; -#else -#include "tft_t_dma.h" -TFT_T_DMA tft = TFT_T_DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, TFT_TOUCH_CS, TFT_TOUCH_INT); -#endif - -bool vgaMode = false; - -static unsigned char palette8[PALETTE_SIZE]; -static unsigned short palette16[PALETTE_SIZE]; -static IntervalTimer myTimer; -volatile boolean vbl=true; -static int skip=0; -static elapsedMicros tius; - -static void vblCount() { - if (vbl) { - vbl = false; - } else { - vbl = true; - } -} - -void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) -{ - if (index>8, - 320 & 0xFF, // YEND = 320 - ST7735_INVON , DELAY, // 7: hack - 10, - ST7735_NORON , DELAY, // 8: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 9: Main screen turn on, no args, w/delay - 255 -#endif -}; - -static void dmaInterrupt() { - dmatx.clearInterrupt(); - curTransfer++; - if (curTransfer >= nbTransfer) { - curTransfer = 0; - if (cancelled) { - dmatx.disable(); - rstop = 1; - } - } - arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2); -} - -static void setDmaStruct() { - uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; - int i=0; - uint16_t col=RGBVAL16(0x00,0x00,0x00);; - while (remaining > 0) { - uint16_t * fb = blocks[i]; - int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining); -#ifdef TFT_DEBUG - Serial.println((unsigned long)blocks[i]); - Serial.println(remaining); -#endif - switch (i) { - case 0: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb0[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0x00); -#endif - break; - case 1: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb1[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0xff); -#endif - break; - case 2: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb2[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0x00,0xff); -#endif - break; - case 3: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb3[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0xff,0x00,0xff); -#endif - break; - } - blocks[i] = fb; - if (blocks[i] == 0) { - Serial.print("ILI9341 allocaltion failed for block "); - Serial.println(i); - delay(10000); - } - - for (int j=0;jATTR_DST = 1; - dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); - dmasettings[i].interruptAtCompletion(); - remaining -= len; - i++; - } - dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); - nbTransfer = i; -#ifdef TFT_DEBUG - Serial.println(nbTransfer); -#endif -} - - -TFT_T_DMA::TFT_T_DMA(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso, uint8_t touch_cs, uint8_t touch_irq) -{ - _cs = cs; - _dc = dc; - _rst = rst; - _mosi = mosi; - _sclk = sclk; - _miso = miso; - pinMode(_dc, OUTPUT); - pinMode(_cs, OUTPUT); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); - if ( (touch_cs != 255) && (touch_irq != 255) ) { - _touch_irq = touch_irq; - _touch_cs = touch_cs; - pinMode(_touch_cs, OUTPUT); - pinMode(touch_irq, INPUT_PULLUP); - digitalWrite(_touch_cs, 1); - } -} - - -void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { - int dx=0; - int dy=0; -#ifdef ST7789 - if (TFT_REALWIDTH == TFT_REALHEIGHT) - { -#ifdef ROTATE_SCREEN - if (!flipped) { - dy += 80; - } -#else - if (flipped) { - dx += 80; - } -#endif - } -#endif - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - SPI.transfer16(x1+dx); - digitalWrite(_dc, 1); - SPI.transfer16(x2+dx); - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - digitalWrite(_dc, 1); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - return; - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - - SPI.transfer16(x1+dx); - SPI.transfer16(x2+dx); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - -void TFT_T_DMA::begin(void) { - SPI.setMOSI(_mosi); - SPI.setMISO(_miso); - SPI.setSCK(_sclk); - SPI.begin(); - - // Initialize display - if (_rst != 0xff) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - const uint8_t *addr = init_commands; - digitalWrite(_cs, 0); -#ifdef ILI9341 - while (1) { - uint8_t count = *addr++; - if (count-- == 0) break; - - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - - while (count-- > 0) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - } - - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(ILI9341_DISPON); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); -#endif -#ifdef ST7789 - uint8_t numCommands, numArgs; - uint16_t ms; - numCommands = *addr++; // Number of commands to follow - while(numCommands--) { // For each command... - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - numArgs = *addr++; // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs > 1) { // For each argument... - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - numArgs--; - } - - if (numArgs) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - if(ms) { - ms = *addr++; // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - digitalWrite(_cs, 1); - SPI.endTransaction(); - delay(ms); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - } - } - digitalWrite(_cs, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - SPI.endTransaction(); - - cancelled = false; - -#ifdef FLIP_SCREEN - flipscreen(true); -#else - flipscreen(false); -#endif -#ifdef ST7789 - if (TFT_REALWIDTH != TFT_REALHEIGHT) - { - flipscreen(true); - } -#endif -}; - - - -void TFT_T_DMA::flipscreen(bool flip) -{ - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(TFT_MADCTL); - digitalWrite(_dc, 1); - if (flip) { - flipped=true; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB); -#endif -#endif - } - else { - flipped=false; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB); -#endif -#endif - } - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - -boolean TFT_T_DMA::isflipped(void) -{ - return(flipped); -} - - -#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) - - -void TFT_T_DMA::startDMA(void) { - curTransfer = 0; - rstop = 0; - //dmatx.begin(true); - dmatx.attachInterrupt(dmaInterrupt); - setDmaStruct(); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - - digitalWrite(_cs, HIGH); - SPI.begin(); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); - - - LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: - LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX - LPSPIP_TCR = 15; // Framesize 16 Bits - //LPSPIP_FCR = 0; // Fifo Watermark - LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable - LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: - dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); - - dmatx = dmasettings[0]; - digitalWrite(_cs, 0); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - dmatx.enable(); -} - - -void TFT_T_DMA::stopDMA(void) { - rstop = 0; - wait(); - delay(50); - cancelled = false; - dmatx.detachInterrupt(); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - SPI.end(); -#ifdef ST7789 - begin(); -#endif -#ifdef ILI9341 - SPI.begin(); - digitalWrite(_cs, 0); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - SPI.endTransaction(); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); -} - -void TFT_T_DMA::wait(void) { - rstop = 1; - unsigned long m = millis(); - cancelled = true; - while (!rstop) { - if ((millis() - m) > 100) break; - delay(10); - asm volatile("wfi"); - }; - rstop = 0; -} - -int TFT_T_DMA::get_frame_buffer_size(int *width, int *height){ - if (width != nullptr) *width = TFT_REALWIDTH; - if (height != nullptr) *height = TFT_REALHEIGHT; - return TFT_REALWIDTH; -} - - -/*********************************************************************************************** - Touch functions - ***********************************************************************************************/ -/* Code based on ... - * - * @file XPT2046.cpp - * @date 19.02.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the XPT2046 driver for Arduino. - */ - -#define ADC_MAX 0x0fff - -void TFT_T_DMA::enableTouchIrq() -{ - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 }; - SPI.transfer((void*)&buf[0],3); - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); -} - -//Default callibration for non flipped -#define TX_MIN 30 -#define TY_MIN 20 -#define TX_MAX 300 -#define TY_MAX 220 - -//Default callibration for flipped -#define TFX_MIN 20 -#define TFY_MIN 25 -#define TFX_MAX 288 -#define TFY_MAX 221 - -static uint16_t txMin; -static uint16_t tyMin; -static uint16_t txMax; -static uint16_t tyMax; - - -void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { - if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) { - txMin = xMin; - tyMin = yMin; - txMax = xMax; - tyMax = yMax; - } - else { - if (flipped) { - txMin = TFX_MIN; - tyMin = TFY_MIN; - txMax = TFX_MAX; - tyMax = TFY_MAX; - } - else { - txMin = TX_MIN; - tyMin = TY_MIN; - txMax = TX_MAX; - tyMax = TY_MAX; - } - } -} - - -void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - if ( TOUCH_ENABLED() ) { - uint16_t x = 0; - uint16_t y = 0; - uint16_t z1 = 0; - uint16_t z2 = 0; - uint8_t i = 0; - int16_t xraw=0, yraw=0; - - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - - for(; i < 15; i++) { - // SPI requirer 32bit aliment - uint8_t buf[12] = { - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00 - }; - SPI.transfer(&buf[0], &buf[0], 12); - y += (buf[1] << 8 | buf[2])>>3; - x += (buf[4] << 8 | buf[5])>>3; - z1 += (buf[7] << 8 | buf[8])>>3; - z2 += (buf[10] << 8 | buf[11])>>3; - } - enableTouchIrq(); - - if(i == 0) { - *oX = 0; - *oY = 0; - *oZ = 0; - } - else { - x /= i; - y /= i; - z1 /= i; - z2 /= i; - } - - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); - int z = z1 + ADC_MAX - z2; - if (flipped) { - xraw = x; - yraw = y; - } else { - xraw = ADC_MAX - x; - yraw = ADC_MAX - y; - } - xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1); - yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1); - - *oX = xraw; - *oY = yraw; - *oZ = z; - } - else - { - *oX = 0; - *oY = 0; - *oZ = 0; - } -} - -void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - readRaw(oX,oY,oZ); - // callibrate ... - if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin); - if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin); - //Serial.print(*oX); - //Serial.print(" "); - //Serial.println(*oY); -} - - -/*********************************************************************************************** - No DMA functions - ***********************************************************************************************/ -void TFT_T_DMA::fillScreenNoDma(uint16_t color) { - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - int i,j; - for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(arx, ary, arx+arw-1, ary+arh-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - bits = *charpt++; - //digitalWrite(_dc, 1); - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - x +=8; -#ifdef ILI9341 - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); -#endif - digitalWrite(_cs, 1); - SPI.endTransaction(); - } - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - - - -/*********************************************************************************************** - DMA functions - ***********************************************************************************************/ -uint16_t * TFT_T_DMA::getLineBuffer(int j) -{ - uint16_t * block=blocks[j>>6]; - return(&block[(j&0x3F)*TFT_REALWIDTH]); -} - -void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) { - uint8_t *buffer=buf; - uint8_t *src; - - int i,j,y=0; - if (width*2 <= TFT_REALWIDTH) { - for (j=0; j>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH]; - for (i=0; i>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x]; - for (i=0; i>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - block=blocks[l>>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt++; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - x +=8; - } -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { - drawSprite(x,y,bitmap, 0,0,0,0); -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) -{ - int bmp_offx = 0; - int bmp_offy = 0; - uint16_t *bmp_ptr; - - int w =*bitmap++; - int h = *bitmap++; - - - if ( (arw == 0) || (arh == 0) ) { - // no crop window - arx = x; - ary = y; - arw = w; - arh = h; - } - else { - if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - int l=ary; - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx]; - bmp_ptr = (uint16_t*)bitmap; - for (int col=0;col -#include -#include -#endif - -#include "tft_t_dma_config.h" - -#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) -#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define R16(rgb) ((rgb>>8)&0xf8) -#define G16(rgb) ((rgb>>3)&0xfc) -#define B16(rgb) ((rgb<<3)&0xf8) - -#define PAL_COLOR_MASK 0xff - -#ifdef LOHRES -#define TFT_WIDTH 240 -#define TFT_REALWIDTH 240 -#else -#define TFT_WIDTH 256 -#define TFT_REALWIDTH 320 -#endif -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - -//#define WIDTH 272 -//#define HEIGHT 228 - -#define LINES_PER_BLOCK 64 -#define NR_OF_BLOCK 4 -#define SCREEN_DMA_NUM_SETTINGS NR_OF_BLOCK - - -#ifdef ILI9341 - -#define ILI9341_NOP 0x00 -#define ILI9341_SWRESET 0x01 -#define ILI9341_RDDID 0x04 -#define ILI9341_RDDST 0x09 - -#define ILI9341_SLPIN 0x10 -#define ILI9341_SLPOUT 0x11 -#define ILI9341_PTLON 0x12 -#define ILI9341_NORON 0x13 - -#define ILI9341_RDMODE 0x0A -#define ILI9341_RDMADCTL 0x0B -#define ILI9341_RDPIXFMT 0x0C -#define ILI9341_RDIMGFMT 0x0D -#define ILI9341_RDSELFDIAG 0x0F - -#define ILI9341_INVOFF 0x20 -#define ILI9341_INVON 0x21 -#define ILI9341_GAMMASET 0x26 -#define ILI9341_DISPOFF 0x28 -#define ILI9341_DISPON 0x29 - -#define ILI9341_CASET 0x2A -#define ILI9341_PASET 0x2B -#define ILI9341_RAMWR 0x2C -#define ILI9341_RAMRD 0x2E - -#define ILI9341_PTLAR 0x30 -#define ILI9341_MADCTL 0x36 -#define ILI9341_VSCRSADD 0x37 -#define ILI9341_PIXFMT 0x3A - -#define ILI9341_FRMCTR1 0xB1 -#define ILI9341_FRMCTR2 0xB2 -#define ILI9341_FRMCTR3 0xB3 -#define ILI9341_INVCTR 0xB4 -#define ILI9341_DFUNCTR 0xB6 - -#define ILI9341_PWCTR1 0xC0 -#define ILI9341_PWCTR2 0xC1 -#define ILI9341_PWCTR3 0xC2 -#define ILI9341_PWCTR4 0xC3 -#define ILI9341_PWCTR5 0xC4 -#define ILI9341_VMCTR1 0xC5 -#define ILI9341_VMCTR2 0xC7 - -#define ILI9341_RDID1 0xDA -#define ILI9341_RDID2 0xDB -#define ILI9341_RDID3 0xDC -#define ILI9341_RDID4 0xDD - -#define ILI9341_GMCTRP1 0xE0 -#define ILI9341_GMCTRN1 0xE1 - -#define ILI9341_MADCTL_MY 0x80 -#define ILI9341_MADCTL_MX 0x40 -#define ILI9341_MADCTL_MV 0x20 -#define ILI9341_MADCTL_ML 0x10 -#define ILI9341_MADCTL_RGB 0x00 -#define ILI9341_MADCTL_BGR 0x08 -#define ILI9341_MADCTL_MH 0x04 - -#define TFT_CASET ILI9341_CASET -#define TFT_PASET ILI9341_PASET -#define TFT_RAMWR ILI9341_RAMWR -#define TFT_MADCTL ILI9341_MADCTL - -#endif - - -#ifdef ST7789 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_RGB 0x00 -#define ST77XX_MADCTL_BGR 0x08 -#define ST77XX_MADCTL_MH 0x04 - -#define TFT_CASET ST7735_CASET -#define TFT_PASET ST7735_RASET -#define TFT_RAMWR ST7735_RAMWR -#define TFT_MADCTL ST7735_MADCTL - -#endif - - - -#ifdef __cplusplus - -class TFT_T_DMA -{ - public: - TFT_T_DMA(uint8_t _CS, uint8_t _DC, uint8_t _RST = 255, uint8_t _MOSI=11, uint8_t _SCLK=13, uint8_t _MISO=12, uint8_t touch_cs=38, uint8_t touch_irq=37); - - void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); - void begin(void); - void flipscreen(bool flip); - boolean isflipped(void); - void startDMA(void); - void stopDMA(); - int get_frame_buffer_size(int *width, int *height); - - // Touch screen functions - #define TOUCH_ENABLED() ((_touch_cs != 255) && (_touch_irq != 255)) - bool isTouching(void) { return ((!TOUCH_ENABLED())?false:(digitalRead(_touch_irq) == LOW)); } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax); - - // NoDMA functions - void writeScreenNoDma(const uint16_t *pcolors); - void fillScreenNoDma(uint16_t color); - void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - // DMA functions - uint16_t * getLineBuffer(int j); - void writeScreen(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int y, uint16_t *buf); - void fillScreen(uint16_t color); - void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - protected: - uint8_t _rst, _cs, _dc; - uint8_t _miso, _mosi, _sclk; - uint8_t _touch_irq=255, _touch_cs=255; - bool flipped=false; - - void wait(void); - void enableTouchIrq(); -}; - -#endif -#endif diff --git a/MCUME_teensy41/teensypce/tft_t_dma_config.h b/MCUME_teensy41/teensypce/tft_t_dma_config.h deleted file mode 100644 index 0a712da..0000000 --- a/MCUME_teensy41/teensypce/tft_t_dma_config.h +++ /dev/null @@ -1,13 +0,0 @@ -#include "platform_config.h" - -//#define ST7789 1 -//#define ILI9341 1 - -#define TFT_LINEARINT 1 -#define LINEARINT_HACK 1 - -//#define FLIP_SCREEN 1 -//#define TFT_DEBUG 1 -#if defined(__IMXRT1052__) || defined(__IMXRT1062__) -//#define TFT_STATICFB 1 -#endif diff --git a/MCUME_teensy41/teensypce/vga_t_dma.h b/MCUME_teensy41/teensypce/vga_t_dma.h deleted file mode 100644 index 81a986b..0000000 --- a/MCUME_teensy41/teensypce/vga_t_dma.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - Wrapping class to extend VGA_T4 to TFT_T_DMA -*/ - -#ifndef _VGA_T_DMAH_ -#define _VGA_T_DMAH_ - -#ifdef __cplusplus -#include -#endif - - -#define RGBVAL16(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) - - - - -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 - -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - - - -#ifdef __cplusplus - -class TFT_T_DMA: public VGA_T4 -{ - public: - // Fake touch screen functions - bool isTouching(void) { return false; } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { } - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { }; - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { } - - // fake DMA functions - void startDMA(void) { }; - void stopDMA(void) { }; - - // fake no DMA functions - void writeScreenNoDma(const vga_pixel *pcolors) { writeScreen(pcolors); } - void fillScreenNoDma(vga_pixel color) { clear(color); } - void drawTextNoDma(int16_t x, int16_t y, const char * text, vga_pixel fgcolor, vga_pixel bgcolor, bool doublesize) { drawText(x,y,text,fgcolor,bgcolor,doublesize); } - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, vga_pixel color) { drawRect(x, y, w, h, color); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap) { drawSprite(x, y, bitmap); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh) { drawSprite(x, y, bitmap, croparx, cropary, croparw, croparh); } -}; - - -#endif -#endif diff --git a/MCUME_teensy41/teensypce/emu.cpp b/MCUME_teensy41/teensypce/wrapemu.cpp similarity index 91% rename from MCUME_teensy41/teensypce/emu.cpp rename to MCUME_teensy41/teensypce/wrapemu.cpp index fb64fab..69519a8 100644 --- a/MCUME_teensy41/teensypce/emu.cpp +++ b/MCUME_teensy41/teensypce/wrapemu.cpp @@ -1,7 +1,6 @@ #include #include "emuapi.h" -#include "tft_t_dma.h" #include "iopins.h" extern "C" { @@ -10,7 +9,7 @@ extern "C" { } -EXTMEM static unsigned char MemPool[8*1024*1024]; +static unsigned char * MemPool; extern "C" uint8 read_rom(int address) { return (MemPool[address]); @@ -23,6 +22,8 @@ extern "C" void write_rom(int address, uint8 val) { void pce_Init(void) { + MemPool = emu_SMalloc(8*1024*1024); + emu_printf("Allocating MEM"); mem_init(); emu_printf("Allocating MEM done"); @@ -65,11 +66,8 @@ void pce_Start(char * filename) emu_printf("init started"); load_rom(filename, 0,0); -#ifdef SOUND_PRESENT - system_init(22050); -#ifdef HAS_SND - emu_sndInit(); -#endif +#ifdef HAS_SND + system_init(22050); #else system_init(0); #endif @@ -98,7 +96,7 @@ void pce_Step(void) { if (( k & MASK_JOY1_DOWN) || ( k & MASK_JOY2_DOWN)) { input.pad[0] |= INPUT_DOWN; } - if ( k & MASK_JOY2_BTN) { + if ( ( k & MASK_JOY1_BTN) || ( k & MASK_JOY2_BTN) ) { input.pad[0] |= INPUT_B2; } diff --git a/MCUME_teensy41/teensypce/emu.h b/MCUME_teensy41/teensypce/wrapemu.h similarity index 65% rename from MCUME_teensy41/teensypce/emu.h rename to MCUME_teensy41/teensypce/wrapemu.h index ad56515..f1442a6 100644 --- a/MCUME_teensy41/teensypce/emu.h +++ b/MCUME_teensy41/teensypce/wrapemu.h @@ -1,5 +1,10 @@ +#ifdef __cplusplus +extern "C" { +#endif extern void pce_Init(void); extern void pce_Step(void); extern void pce_Start(char * filename); extern void pce_Input(int click); - +#ifdef __cplusplus +} +#endif diff --git a/MCUME_teensy41/teensysms/emuapi.cpp b/MCUME_teensy41/teensysms/emuapi.cpp index 97a570f..e128cca 100644 --- a/MCUME_teensy41/teensysms/emuapi.cpp +++ b/MCUME_teensy41/teensysms/emuapi.cpp @@ -5,25 +5,31 @@ extern "C" { #include "iopins.h" } -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#else -#include "tft_t_dma.h" -#endif +#include -#ifdef HAS_USBKEY +#ifdef HAS_USB #include "USBHost_t36.h" // Read this header first for key info USBHost myusb; USBHub hub1(myusb); +#ifdef HAS_USBKEY KeyboardController keyboard1(myusb); USBHIDParser hid1(myusb); MouseController mouse1(myusb); +#endif +#ifdef HAS_USBMIDI MIDIDevice midi1(myusb); #endif +#ifdef HAS_USBJOY +#define COUNT_JOYSTICKS 4 +JoystickController joysticks[COUNT_JOYSTICKS](myusb); +#endif +#endif static bool emu_writeConfig(void); static bool emu_readConfig(void); static bool emu_eraseConfig(void); +static bool emu_writeGfxConfig(char * display_type); +static int emu_readGfxConfig(void); static bool mouseDetected = false; static bool keyboardDetected = false; @@ -34,8 +40,9 @@ static File file; #define MAX_FILES 64 #define AUTORUN_FILENAME "autorun.txt" +#define GFX_CFG_FILENAME "gfxmode.txt" -#define MAX_FILENAME_SIZE 36 +#define MAX_FILENAME_SIZE 34 #define MAX_MENULINES 9 #define TEXT_HEIGHT 16 #define TEXT_WIDTH 8 @@ -53,7 +60,8 @@ static File file; #define MENU_VGA_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) #define MENU_VGA_YOFFSET (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37) -extern TFT_T_DMA tft; +#include "t4_dsp.h" +T4_DSP tft; static int nbFiles=0; static int curFile=0; @@ -65,6 +73,8 @@ static char selected_filename[MAX_FILENAME_SIZE]=""; static char second_selected_filename[MAX_FILENAME_SIZE]=""; static bool menuRedraw=true; static bool autorun=false; +static bool vgahires=false; + static const unsigned short * keys; #ifdef TEECOMPUTER @@ -158,6 +168,29 @@ void emu_Free(void * pt) free(pt); } +#define SMEMPOOL (0x800000) +EXTMEM static unsigned char slowmem[SMEMPOOL]; +static int slowmempt = 0; + +void * emu_SMalloc(unsigned int size) +{ + void * mem = (void*)&slowmem[slowmempt]; + slowmempt += size; + + if ( slowmempt > SMEMPOOL ) { + mem = NULL; + emu_printf("failure to allocate slow"); + } + else { + emu_printf("could allocate slow static "); + emu_printf(size); + } + return mem; +} + +void emu_SFree(void * pt) +{ +} /******************************** * Input and keyboard ********************************/ @@ -329,6 +362,12 @@ int emu_ReadKeys(void) #endif if ( row & 0x02 ) retval |= MASK_JOY2_BTN; + +#ifdef EXTPAD + if ( sh_pressed ) retval |= MASK_KEY_USER3; + if ( fn_pressed ) retval |= MASK_KEY_USER1; + digitalWrite(KLED, 0); +#else // Handle LED flash uint32_t time_ms=millis(); if ((time_ms-last_t_ms) > 100) { @@ -412,8 +451,9 @@ int emu_ReadKeys(void) if ( key_fn ) retval |= MASK_KEY_USER2; if ( ( key_fn ) && (keymatrix[4] == 0x10 )) retval |= MASK_KEY_USER1; +#endif - if ( (key_fn) && (key_sh) ) + if ( (fn_pressed) && (sh_pressed) ) #else if ( ((retval & (MASK_KEY_USER1+MASK_KEY_USER2)) == (MASK_KEY_USER1+MASK_KEY_USER2)) || (retval & MASK_KEY_USER4 ) ) @@ -453,8 +493,10 @@ int emu_ReadKeys(void) while (true) { ; } -#endif +#endif } + + emu_GetJoystick(); return (retval); } @@ -607,7 +649,7 @@ int emu_setKeymap(int index) { } int emu_GetMouse(int *x, int *y, int *buts) { -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBKEY) if (mouse1.available()) { *buts = mouse1.getButtons(); *x = mouse1.getMouseX(); @@ -620,7 +662,23 @@ int emu_GetMouse(int *x, int *y, int *buts) { return 0; } -#ifdef HAS_USBKEY +int emu_GetJoystick(void) { +#if defined(HAS_USB) && (HAS_USBJOY) + for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) { + if (joysticks[joystick_index].available()) { + uint64_t axis_mask = joysticks[joystick_index].axisMask(); + uint64_t axis_changed_mask = joysticks[joystick_index].axisChangedMask(); + uint32_t buttons = joysticks[joystick_index].getButtons(); + Serial.printf("Joystick(%d): buttons = %x", joystick_index, buttons); + Serial.println(); + } + } + return 1; +#endif + return 0; +} + +#if defined(HAS_USB) && (HAS_USBKEY) void OnPress(auto key) { keyboardDetected = true; @@ -764,7 +822,7 @@ int emu_KeyboardDetected(void) { return (keyboardDetected?1:0); } -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) static unsigned char midiBuffer[16]; static unsigned char midiLastCmd=0; static int midiDataCnt=0; @@ -772,8 +830,7 @@ static int midiCmdNbParam=0; #endif void emu_MidiOnDataReceived(unsigned char value) { - -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) //Serial.println(value, HEX); //10000000 = 128 = note off //10010000 = 144 = note on @@ -941,6 +998,7 @@ void emu_MidiOnDataReceived(unsigned char value) { /******************************** * Menu file loader UI ********************************/ +#ifdef FILEBROWSER static int readNbFiles(void) { int totalFiles = 0; @@ -970,8 +1028,6 @@ static int readNbFiles(void) { return totalFiles; } - - void backgroundMenu(void) { menuRedraw=true; tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00)); @@ -981,11 +1037,13 @@ void backgroundMenu(void) { int handleMenu(uint16_t bClick) { if (autorun) { + toggleMenu(false); + menuRedraw=false; return (ACTION_RUN1); } int action = ACTION_NONE; - if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) ) { + if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) || ( bClick & MASK_KEY_USER2 ) ) { char newpath[MAX_FILENAME_PATH]; strcpy(newpath, selection); strcat(newpath, "/"); @@ -996,17 +1054,31 @@ int handleMenu(uint16_t bClick) File file = SD.open(selection); if (file.isDirectory()) { curFile = 0; - nbFiles = readNbFiles(); + nbFiles = readNbFiles(); + menuRedraw=true; } - else { - action = ACTION_RUN1; + else + { #ifdef TEECOMPUTER - if (key_extmode) { + if ( (key_extmode) || ( key_sh) ) { emu_writeConfig(); } + if ( tft.getMode() < MODE_VGA_320x240) { + if ( bClick & MASK_KEY_USER2 ) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + } + //emu_SwapJoysticks(0); #endif + toggleMenu(false); + menuRedraw=false; + return (ACTION_RUN1); } - menuRedraw=true; } else if ( bClick & MASK_KEY_USER1 ) { menuRedraw=true; @@ -1015,19 +1087,14 @@ int handleMenu(uint16_t bClick) strcat(second_selection, "/"); strcat(second_selection, second_selected_filename); action = ACTION_RUN2; - } - else if ( bClick & MASK_KEY_USER2 ) { - menuRedraw=true; - //action = ACTION_RUN3; - emu_SwapJoysticks(0); - } + } else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) { if (curFile!=0) { menuRedraw=true; curFile--; } } - else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { + else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { if ((curFile-9)>=0) { menuRedraw=true; curFile -= 9; @@ -1042,7 +1109,7 @@ int handleMenu(uint16_t bClick) menuRedraw=true; } } - else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { + else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { if ((curFile<(nbFiles-9)) && (nbFiles)) { curFile += 9; menuRedraw=true; @@ -1099,12 +1166,12 @@ int handleMenu(uint16_t bClick) return (action); } -bool menuActive(void) +int menuActive(void) { - return (menuOn); + return (menuOn?1:0); } -void toggleMenu(bool on) { +void toggleMenu(int on) { if (on) { menuOn=true; backgroundMenu(); @@ -1122,7 +1189,7 @@ char * menuSecondSelection(void) { return (second_selection); } - +#endif /******************************** * OSKB handling @@ -1140,8 +1207,9 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) char c[4] = {' ',0,' ',0}; const char * cpt = str; int i=0; - int fb_width,fb_height; - tft.get_frame_buffer_size(&fb_width, &fb_height); + int fb_width,fb_height,fbstride; + + fbstride = tft.get_frame_buffer_size(&fb_width, &fb_height); int ypos = (bottom?(fb_height-2*8):0); int line = row + (bottom?2:0); while ((c[1] = *cpt++)) @@ -1150,7 +1218,7 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0); else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff); if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff); - tft.drawTextNoDma(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); + tft.drawText(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); i++; } } @@ -1248,7 +1316,7 @@ int handleOSKB(void) { return retval; } -void toggleOSKB(bool forceon) { +void toggleOSKB(int forceon) { if (forceon) { oskbOn = true; drawOSKB(); @@ -1332,6 +1400,17 @@ int emu_FileRead(void * buf, int size, int handler) #endif } +int emu_FileWrite(void * buf, int size, int handler) +{ +// emu_printf("emu_FileWrite"); +// emu_printi(handler); +#ifdef HCFH + return (file.write(buf, size)); +#else + return (getFileHandler(handler).write(buf, size)); +#endif +} + int emu_FileGetc(int handler) { // emu_printf("FileGetc"); // emu_printi(handler); @@ -1404,6 +1483,9 @@ unsigned int emu_FileSize(const char * filepath) emu_printf(filesize); lofile.close(); } + else { + emu_printf("filesize failed"); + } return(filesize); } @@ -1489,6 +1571,48 @@ static bool emu_eraseConfig(void) SD.remove (ROMSDIR "/" AUTORUN_FILENAME); } +static bool emu_writeGfxConfig(char * display_type) +{ + bool retval = false; + SD.remove ("/" GFX_CFG_FILENAME); + if (strcmp(display_type, "VGA")) { + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(display_type, strlen(display_type)) != strlen(display_type)) { + emu_printf("GFX config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + } + return retval; +} + +#define CFG_VGA 0 +#define CFG_ILI 1 +#define CFG_ST 2 + +static int emu_readGfxConfig(void) +{ + int retval = CFG_VGA; // No file = VGA + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + if (filesize == 2) // "ST" + { + retval = CFG_ST; + } + else if (filesize == 3) // "ILI" + { + retval = CFG_ILI; + } + lofile.close(); + } + return retval; +} + /******************************** * File IO compatibility ********************************/ @@ -1670,62 +1794,249 @@ FRESULT f_mkdir (const char* path) /******************************** - * Initialization + * GFX wrapper ********************************/ -void emu_init(void) +static unsigned short palette16[PALETTE_SIZE]; +static IntervalTimer myTimer; +volatile boolean vbl=true; +volatile boolean vgatimervsync=false; +static void (*vblCallback)(void) = nullptr; +static int skip=0; + +static void vblCount() { + if (vbl) { + vbl = false; + } else { + vbl = true; + } +} + +void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) +{ + if (index= MODE_VGA_320x240 ) { + if (vgatimervsync) { + while (vbl==vb) {}; + } + else { + tft.waitSync(); + } + } + else { + while (vbl==vb) {}; + } + if (vblCallback != nullptr) { + vblCallback(); + } +} + +void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride) +{ + if (skip == 0) { + tft.writeScreenPal(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); + } +} +void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLinePal(width,height,line, VBuf, palette16); + } +} + +void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine(width,height,line, VBuf); + } +} + +void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine8(width,height,line, VBuf, palette16); + } +} + +int emu_IsVga(void) +{ + return (tft.getMode() >= MODE_VGA_320x240?1:0); +} + +int emu_IsVgaHires(void) +{ + return (tft.getMode() >= MODE_VGA_640x240?1:0); +} + +int emu_FrameSkip(void) +{ + return skip; +} + + +/******************************** + * AUDIO wrapper +********************************/ +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +AudioPlaySystem mymixer; + +void emu_sndInit() { + Serial.println("sound init"); + mymixer.begin_audio(256, mymixer.snd_Mixer); + mymixer.start(); +} + +void emu_sndPlaySound(int chan, int volume, int freq) +{ + if (chan < 6) { + mymixer.sound(chan, freq, volume); + } + /* + Serial.print(chan); + Serial.print(":" ); + Serial.print(volume); + Serial.print(":" ); + Serial.println(freq); + */ +} + +void emu_sndPlayBuzz(int size, int val) { + mymixer.buzz(size,val); + //Serial.print((val==1)?1:0); + //Serial.print(":"); + //Serial.println(size); +} +#endif + +/******************************** + * Initialization +********************************/ +void emu_init(int hires) { Serial.begin(115200); + vgahires = hires; -#ifdef HAS_USBKEY +#ifdef HAS_USB myusb.begin(); +#ifdef HAS_USBKEY keyboard1.attachPress(OnPress); keyboard1.attachRelease(OnRelease); #endif +#endif - while (!SD.begin(SD_CS)) +#ifdef FILEBROWSER + if (!SD.begin(SD_CS)) { - Serial.println("SD begin failed, retrying..."); - delay(1000); + Serial.println("No SD card detected"); } strcpy(selection,ROMSDIR); - FileHandlersInit(); - nbFiles = readNbFiles(); - - Serial.print("SD initialized, files found: "); Serial.println(nbFiles); +#endif emu_InitJoysticks(); #ifdef SWAP_JOYSTICK - joySwapped = true; + joySwapped = true; #else - joySwapped = false; + joySwapped = false; #endif -#ifdef TEECOMPUTER -#ifndef HAS_T4_VGA - tft.flipscreen(false); -#endif -#endif int keypressed = emu_ReadKeys(); +#ifdef HAS_T4_VGA + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } +#else + int gfx_mode = CFG_VGA; // default +#ifdef FILEBROWSER + gfx_mode = emu_readGfxConfig(); +#endif + // Force VGA if UP pressed + if (keypressed & MASK_JOY2_UP) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("VGA"); +#endif + gfx_mode = CFG_VGA; + } + else { + if (keypressed & MASK_JOY2_LEFT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ST"); +#endif + gfx_mode = CFG_ST; + } + else if (keypressed & MASK_JOY2_RIGHT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ILI"); +#endif + gfx_mode = CFG_ILI; + } + } + if (gfx_mode == CFG_VGA) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + else + { + tft.begin(gfx_mode == CFG_ILI?MODE_TFTILI_320x240:MODE_TFTST_320x240); + } +#endif + if (keypressed & MASK_JOY2_DOWN) { tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) ); tft.drawTextNoDma(64,48, (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); +#ifdef FILEBROWSER emu_eraseConfig(); delay(1000); +#endif } else { +#ifdef FILEBROWSER if (emu_readConfig()) { autorun = true; } +#endif } +#ifdef FILEBROWSER toggleMenu(true); +#endif } -void emu_start(void) +void emu_start(int vblms, void * callback, int forcetimervsync) { + vgatimervsync = forcetimervsync?true:false; + tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); + tft.startRefresh(); + if (callback != nullptr) { + vblCallback = callback; + } + + myTimer.begin(vblCount, vblms); +#ifdef HAS_SND + emu_sndInit(); +#endif usbnavpad = 0; } diff --git a/MCUME_teensy41/teensysms/emuapi.h b/MCUME_teensy41/teensysms/emuapi.h index cbfa376..5dd6130 100644 --- a/MCUME_teensy41/teensysms/emuapi.h +++ b/MCUME_teensy41/teensysms/emuapi.h @@ -2,126 +2,14 @@ #define EMUAPI_H #include "platform_config.h" - -#define CUSTOM_SND 1 -//#define TIMER_REND 1 - -#define EXTRA_HEAP 0x10 //0x9000 - -// Title: < > -#define TITLE " Master System Emulator " -#define ROMSDIR "/sms" - -#define emu_Init(ROM) {sms_Init(); sms_Start(ROM);} -#define emu_Step(x) {sms_Step();} -#define emu_Input(x) {sms_Input(x);} - -#define MAX_FILENAME_PATH 64 -#define NB_FILE_HANDLER 4 -#define PALETTE_SIZE 32 -#define VID_FRAME_SKIP 0x0 -#define TFT_VBUFFER_YCROP 0 -#define SINGLELINE_RENDERING 1 - -#define R32(rgb) ((rgb>>16)&0xff) -#define G32(rgb) ((rgb>>8)&0xff) -#define B32(rgb) (rgb & 0xff) +#include "emucfg.h" #define ACTION_NONE 0 -#define ACTION_MAXKBDVAL 16 -#define ACTION_EXITKBD 128 -#define ACTION_RUN1 129 -#define ACTION_RUN2 130 -#define ACTION_RUN3 131 - -#ifdef KEYMAP_PRESENT - -#define keylables_map0_0 (char *)"qwertyuiop\x1a" -#define keylables_map0_1 (char *)" asdfghjkl\x19" -#define keylables_map0_2 (char *)" zxcvbnm,.;/" -#define keylables_map0_3 (char *)" +\x10-" -const unsigned short key_map0[] = { - 'q','w','e','r','t','y','u','i','o','p',157, //lowecase - 0,'a','s','d','f','g','h','j','k','l',0x0D, - 0,'z','x','c','v','b','n','m',',','.',';','/', - 145,157,29,17, - 0,'+',' ','-' - }; - -#define keylables_map1_0 (char *)"QWERTYUIOP@" -#define keylables_map1_1 (char *)" ASDFGHJKL\x19" -#define keylables_map1_2 (char *)" ZXCVBNM<>:?" -#define keylables_map1_3 (char *)" =\x10_" -const unsigned short key_map1[] = { - 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase - 0,'A','S','D','F','G','H','J','K','L',0x0D, - 0,'Z','X','C','V','B','N','M','<','>',':','?', - 145,157,29,17, - 0,'=',' ','_' - }; - -#define keylables_map2_0 (char *)"!\"#$%^&*()@" -#define keylables_map2_1 (char *)" |\\[]{} " -#define keylables_map2_2 (char *)" <>:?" -#define keylables_map2_3 (char *)" =\x10_" -const unsigned short key_map2[] = { - '!','"','#','$','%','^','&','*','(',')','@', // shiftothers - 0, '|','\\','[',']','{','}','\'',0,0,0, - 0, 0,0,0,0,0,0,0,'<','>',':','?', - 0,0,0,0, - 0,'=',' ','_' - }; - -#define keylables_map3_0 (char *)"1234567890 " -#define keylables_map3_1 (char *)" " -#define keylables_map3_2 (char *)" " -#define keylables_map3_3 (char *)" " - -const unsigned short key_map3[] = { - '1','2','3','4','5','6','7','8','9','0',0, // digit keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map4_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " -#define keylables_map4_1 (char *)" " -#define keylables_map4_2 (char *)" " -#define keylables_map4_3 (char *)" " - -const unsigned short key_map4[] = { - 133,134,135,136,137,138,139,140,0,0,0, // function keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map5_0 (char *)" " -#define keylables_map5_1 (char *)" " -#define keylables_map5_2 (char *)" " -#define keylables_map5_3 (char *)" " - -const unsigned short key_map5[] = { - 0,0,0,0,0,0,0,0,0,0,0, // extra keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -const unsigned short matkeys[] = { - 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 - 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 - 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 - 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN - 0x510,0x010,0x110,0x310, // row 4 - }; - -#endif - +#define ACTION_RUN1 1 +#define ACTION_RUN2 2 +#define FORCE_VGATIMERVSYNC 1 +#define SUPPORT_HIRES 1 #define MASK_JOY2_RIGHT 0x0001 #define MASK_JOY2_LEFT 0x0002 @@ -138,22 +26,25 @@ const unsigned short matkeys[] = { #define MASK_JOY1_BTN 0x1000 #define MASK_KEY_USER4 0x2000 +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) #ifdef __cplusplus extern "C" { +extern void emu_init(int hires=0); +extern void emu_start(int vblms, void * callback, int forcetimervsync=0); #endif - -extern void emu_init(void); -extern void emu_start(void); extern void emu_printf(const char * text); extern void emu_printi(int val); extern void emu_printh(int val); extern void * emu_Malloc(unsigned int size); extern void * emu_MallocI(unsigned int size); extern void emu_Free(void * pt); +extern void * emu_SMalloc(unsigned int size); +extern void emu_SFree(void * pt); extern int emu_FileOpen(const char * filepath, const char * mode); extern int emu_FileRead(void * buf, int size, int handler); +extern int emu_FileWrite(void * buf, int size, int handler); extern int emu_FileGetc(int handler); extern int emu_FileSeek(int handler, int seek, int origin); extern int emu_FileTell(int handler); @@ -164,24 +55,23 @@ extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size); extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek); extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index); -extern void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride); -extern void emu_DrawLine(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line); extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line); +extern void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride); extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line); -extern void emu_CopyLine(int width, int height, int ysrc, int ydst); extern void emu_DrawVsync(void); extern int emu_FrameSkip(void); -extern void * emu_LineBuffer(int line); -extern void emu_tweakVideo(int shiftdelta, int numdelta, int denomdelta); +extern int emu_IsVga(void); +extern int emu_IsVgaHires(void); -extern bool menuActive(void); +extern int menuActive(void); extern char * menuSelection(void); extern char * menuSecondSelection(void); -extern void toggleMenu(bool on); +extern void toggleMenu(int on); extern int handleMenu(unsigned short bClick); extern int handleOSKB(void); -extern void toggleOSKB(bool forceon); +extern void toggleOSKB(int forceon); extern void emu_InitJoysticks(void); extern int emu_SwapJoysticks(int statusOnly); @@ -190,6 +80,7 @@ extern int emu_ReadKeys(void); extern int emu_GetPad(void); extern int emu_GetMouse(int *x, int *y, int *buts); extern int emu_MouseDetected(void); +extern int emu_GetJoystick(void); extern int emu_KeyboardDetected(void); extern int emu_ReadAnalogJoyX(int min, int max); extern int emu_ReadAnalogJoyY(int min, int max); diff --git a/MCUME_teensy41/teensysms/emucfg.h b/MCUME_teensy41/teensysms/emucfg.h new file mode 100644 index 0000000..b8006c8 --- /dev/null +++ b/MCUME_teensy41/teensysms/emucfg.h @@ -0,0 +1,115 @@ +#ifndef EMUCFG_H +#define EMUCFG_H + +#include "wrapemu.h" + +// Title: < > +#define TITLE " Master System Emulator " +#define ROMSDIR "/sms" + +#define emu_Init(ROM) {sms_Init(); sms_Start(ROM);} +#define emu_Step(x) {sms_Step();} +#define emu_Input(x) {sms_Input(x);} + +#define MAX_FILENAME_PATH 64 +#define NB_FILE_HANDLER 4 + +#define PALETTE_SIZE 32 +#define VID_FRAME_SKIP 0x0 +#define TFT_VBUFFER_YCROP 0 +#define SINGLELINE_RENDERING 1 +#define CUSTOM_SND 1 +//#define TIMER_REND 1 +//#define EXTPAD 1 +#define EXTRA_HEAP 0x10 +#define FILEBROWSER 1 + + +#ifdef KEYMAP_PRESENT + +#define keylables_map0_0 (char *)"qwertyuiop\x1a" +#define keylables_map0_1 (char *)" asdfghjkl\x19" +#define keylables_map0_2 (char *)" zxcvbnm,.;/" +#define keylables_map0_3 (char *)" +\x10-" +const unsigned short key_map0[] = { + 'q','w','e','r','t','y','u','i','o','p',157, //lowecase + 0,'a','s','d','f','g','h','j','k','l',0x0D, + 0,'z','x','c','v','b','n','m',',','.',';','/', + 145,157,29,17, + 0,'+',' ','-' + }; + +#define keylables_map1_0 (char *)"QWERTYUIOP@" +#define keylables_map1_1 (char *)" ASDFGHJKL\x19" +#define keylables_map1_2 (char *)" ZXCVBNM<>:?" +#define keylables_map1_3 (char *)" =\x10_" +const unsigned short key_map1[] = { + 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase + 0,'A','S','D','F','G','H','J','K','L',0x0D, + 0,'Z','X','C','V','B','N','M','<','>',':','?', + 145,157,29,17, + 0,'=',' ','_' + }; + +#define keylables_map2_0 (char *)"!\"#$%^&*()@" +#define keylables_map2_1 (char *)" |\\[]{} " +#define keylables_map2_2 (char *)" <>:?" +#define keylables_map2_3 (char *)" =\x10_" +const unsigned short key_map2[] = { + '!','"','#','$','%','^','&','*','(',')','@', // shiftothers + 0, '|','\\','[',']','{','}','\'',0,0,0, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 0,0,0,0, + 0,'=',' ','_' + }; + +#define keylables_map3_0 (char *)"1234567890 " +#define keylables_map3_1 (char *)" " +#define keylables_map3_2 (char *)" " +#define keylables_map3_3 (char *)" " + +const unsigned short key_map3[] = { + '1','2','3','4','5','6','7','8','9','0',0, // digit keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map4_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " +#define keylables_map4_1 (char *)" " +#define keylables_map4_2 (char *)" " +#define keylables_map4_3 (char *)" " + +const unsigned short key_map4[] = { + 133,134,135,136,137,138,139,140,0,0,0, // function keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map5_0 (char *)" " +#define keylables_map5_1 (char *)" " +#define keylables_map5_2 (char *)" " +#define keylables_map5_3 (char *)" " + +const unsigned short key_map5[] = { + 0,0,0,0,0,0,0,0,0,0,0, // extra keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +const unsigned short matkeys[] = { + 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 + 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 + 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 + 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN + 0x510,0x010,0x110,0x310, // row 4 + }; + +#endif + +#endif diff --git a/MCUME_teensy41/teensysms/platform_config.h b/MCUME_teensy41/teensysms/platform_config.h index 5045b11..914d152 100644 --- a/MCUME_teensy41/teensysms/platform_config.h +++ b/MCUME_teensy41/teensysms/platform_config.h @@ -4,13 +4,13 @@ #define TEECOMPUTER 1 #ifdef TEECOMPUTER -//#define ILI9341 1 -#define ST7789 1 #define TFTSPI1 1 //#define HAS_T4_VGA 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 -//#define INVX 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 #define PT8211 1 #else @@ -19,7 +19,11 @@ //#define INVX 1 #define INVY 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 +#define PT8211 1 #endif diff --git a/MCUME_teensy41/teensysms/render.c b/MCUME_teensy41/teensysms/render.c index 9d4966e..9e40f92 100644 --- a/MCUME_teensy41/teensysms/render.c +++ b/MCUME_teensy41/teensysms/render.c @@ -1,4 +1,5 @@ #include "shared.h" +#include "emuapi.h" /* Background drawing function */ static void (*render_bg)(int line); @@ -37,9 +38,6 @@ static int vp_vend; static int vp_hstart; static int vp_hend; -extern void emu_DrawLine(unsigned short *src, int width , int height, int line); -extern void emu_printf(char * text); - /* Macros to access memory 32-bits at a time (from MAME's drawgfx.c) */ #ifdef ALIGN_DWORD @@ -174,7 +172,7 @@ void render_line(int line) } for (int i=0; i +#include + +#include "font8x8.h" + +// TFT constants and variables +#define TFT_LINEARINT 1 +#define LINEARINT_HACK 1 +#define DMA_LINES_PER_BLOCK 64 +#define DMA_NUM_SETTINGS 4 + +#define TFT_SWRESET 0x01 +#define TFT_SLPOUT 0x11 +#define TFT_INVON 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_MADCTL 0x36 +#define TFT_PIXFMT 0x3A +#define TFT_MADCTL_MY 0x80 +#define TFT_MADCTL_MX 0x40 +#define TFT_MADCTL_MV 0x20 +#define TFT_MADCTL_ML 0x10 +#define TFT_MADCTL_RGB 0x00 +#define TFT_MADCTL_BGR 0x08 +#define TFT_MADCTL_MH 0x04 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) +//#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) +//#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) +//#define R16(rgb) ((rgb>>8)&0xf8) +//#define G16(rgb) ((rgb>>3)&0xfc) +//#define B16(rgb) ((rgb<<3)&0xf8) + +// LPSPI4 = SPI0 in Teensy 4.0 +// LPSPI3 = SPI1 in Teensy 4.0 +// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) + +#ifdef TFTSPI1 +#define SPI SPI1 +#define LPSPIP_TDR LPSPI3_TDR +#define LPSPIP_CR LPSPI3_CR +#define LPSPIP_CFGR1 LPSPI3_CFGR1 +#define LPSPIP_TCR LPSPI3_TCR +#define LPSPIP_DER LPSPI3_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX +#else +#define LPSPIP_TDR LPSPI4_TDR +#define LPSPIP_CR LPSPI4_CR +#define LPSPIP_CFGR1 LPSPI4_CFGR1 +#define LPSPIP_TCR LPSPI4_TCR +#define LPSPIP_DER LPSPI4_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX +#endif + +#define SPICLOCK 60000000 +#define SPI_MODE SPI_MODE0 + +// VGA constants and macros +typedef uint8_t vga_pixel; +#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) + +static DMASetting dmasettings[DMA_NUM_SETTINGS]; +static DMAChannel dmatx; +static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K +static volatile uint8_t rstop = 0; +static volatile bool cancelled = false; +static volatile uint8_t curTransfer = 0; +static uint8_t nbTransfer = 0; +static uint16_t * tft_buffer; +static int tft_width; +static int tft_height; +static int tft_stride; + +#define DELAY_MASK 0x80 +PROGMEM static const uint8_t init_commands[] = { + 1+DELAY_MASK, TFT_SWRESET, 150, + 1+DELAY_MASK, TFT_SLPOUT, 255, + 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, + 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, + 1, TFT_INVON, + 1, TFT_DISPON, + 0 +}; + +// VGA constants and variables +// Objective: +// generates VGA signal fully in hardware with as little as possible CPU help + +// Principle: +// QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) +// 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate +// RGB out, combined to create 8bits(/12bits) output. + +// Note: +// - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels +// - experimental resolution: 352x240,352x480 +// - experimental resolution: 512x240,512x480 (not stable) +// - video memory is allocated using malloc in T4 heap +// - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing +// but tried to be compensated by pixel shifting +// - Default is 8bits RRRGGGBB (332) +// But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! +// - Only ok at 600MHz else some disturbances visible + + + +#define TOP_BORDER 40 +#define PIN_HBLANK 15 + +#define PIN_R_B2 33 +#define PIN_R_B1 4 +#define PIN_R_B0 3 +#define PIN_G_B2 2 +#define PIN_G_B1 13 +#define PIN_G_B0 11 +#define PIN_B_B1 12 +#define PIN_B_B0 10 + + +#define DMA_HACK 0x80 + +#define R16(rgb) ((rgb>>8)&0xf8) +#define G16(rgb) ((rgb>>3)&0xfc) +#define B16(rgb) ((rgb<<3)&0xf8) + +// VGA 640x480@60Hz +// Screen refresh rate 60 Hz +// Vertical refresh 31.46875 kHz +// Pixel freq. 25.175 MHz +// +// Visible area 640 25.422045680238 us +// Front porch 16 0.63555114200596 us +// Sync pulse 96 3.8133068520357 us +// Back porch 48 1.9066534260179 us +// Whole line 800 31.777557100298 us + +#define frame_freq 60.0 // Hz +#define line_freq 31.46875 // KHz +#define pix_freq (line_freq*800) // KHz (25.175 MHz) + +// pix_period = 39.7ns +// H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) +#define frontporch_pix 20 //16 +#define backporch_pix 44 //48 + +// Flexio Clock +// PLL3 SW CLOCK (3) => 480 MHz +// PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) +#define FLEXIO_CLK_SEL_PLL3 3 +#define FLEXIO_CLK_SEL_PLL5 2 + +/* Set video PLL */ +// There are /1, /2, /4, /8, /16 post dividers for the Video PLL. +// The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, +// and CCM_ANALOG_MISC2 register sets according to the following equation. +// PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + +// nfact: +// This field controls the PLL loop divider. +// Valid range for DIV_SELECT divider value: 27~54. + +#define POST_DIV_SELECT 2 + +// Full buffer including back/front porch +static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; +static uint32_t dstbuffer __attribute__((aligned(32))); + +// Visible vuffer +static vga_pixel * vga_buffer; +static int vga_width; +static int vga_height; +static int vga_stride; + +static int maxpixperline; +static int left_border; +static int right_border; +static int line_double; +static int pix_shift; +static int ref_div_select; +static int ref_freq_num; +static int ref_freq_denom; +static int ref_pix_shift; +static int combine_shiftreg; + +#ifdef DEBUG +static uint32_t ISRTicks_prev = 0; +volatile uint32_t ISRTicks = 0; +#endif + +uint8_t T4_DSP::_rst; +uint8_t T4_DSP::_cs; +uint8_t T4_DSP::_dc; +uint8_t T4_DSP::_mosi; +uint8_t T4_DSP::_sclk; +uint8_t T4_DSP::_vsync_pin = -1; +DMAChannel T4_DSP::flexio1DMA; +DMAChannel T4_DSP::flexio2DMA; + +static volatile uint32_t VSYNC = 0; +static volatile uint32_t currentLine=0; +#define NOP asm volatile("nop\n\t"); +static gfx_mode_t gfxmode = MODE_UNDEFINED; + + +FASTRUN void T4_DSP::TFT_isr(void) { + dmatx.clearInterrupt(); + curTransfer++; + if (curTransfer >= nbTransfer) { + curTransfer = 0; + if (cancelled) { + dmatx.disable(); + rstop = 1; + } + } + arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); +} + +FASTRUN void T4_DSP::QT3_isr(void) { + TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); + TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); + + cli(); + + // V-PULSE + if (currentLine > 0) { + digitalWrite(_vsync_pin, 1); + VSYNC = 0; + } else { + digitalWrite(_vsync_pin, 0); + VSYNC = 1; + } + + currentLine++; + currentLine = currentLine % 525; + + + uint32_t y = (currentLine - TOP_BORDER) >> line_double; + // Visible area + + if (y >= 0 && y < vga_height) { + // Disable DMAs + //DMA_CERQ = flexio2DMA.channel; + //DMA_CERQ = flexio1DMA.channel; + + // Setup source adress + // Aligned 32 bits copy + unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; + flexio2DMA.TCD->SADDR = p; + if (pix_shift & DMA_HACK) + { + // Unaligned copy + uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; + flexio1DMA.TCD->SADDR = p2; + } + else { + p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 + flexio1DMA.TCD->SADDR = p; + } + + // Enable DMAs + //flexio2DMA.enable(); + //flexio1DMA.enable(); + DMA_SERQ = flexio2DMA.channel; + DMA_SERQ = flexio1DMA.channel; + arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); + } + sei(); + +#ifdef DEBUG + ISRTicks++; +#endif + asm volatile("dsb"); +} + +static void setDmaStruct() { + uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; + uint16_t * fb = (uint16_t*)malloc(remaining); + tft_buffer = fb; + tft_width = TFT_WIDTH; + tft_height = TFT_HEIGHT; + tft_stride = TFT_WIDTH; + uint16_t col=RGBVAL16(0x00,0x00,0x00); + int i=0; + while (remaining > 0) { + int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); + blocks[i] = fb; + for (int j=0;jATTR_DST = 1; + dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); + dmasettings[i].interruptAtCompletion(); + fb += len/2; + remaining -= len; + i++; + } + dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); + nbTransfer = i; +} + +static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 +{ +//if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; + CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE + | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 + | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); + CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; + CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock + const int div_post_pll = 1; // other values: 2,4 + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass +} + +T4_DSP::T4_DSP() +{ + _cs = TFT_CS; + _dc = TFT_DC; + _rst = TFT_RST; + _mosi = TFT_MOSI; + _sclk = TFT_SCLK; + pinMode(_dc, OUTPUT); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, 1); + digitalWrite(_dc, 1); + _vsync_pin = 8; +} + + +void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { + int dx=0; + int dy=0; + digitalWrite(_dc, 0); + SPI.transfer(TFT_CASET); + digitalWrite(_dc, 1); + SPI.transfer16(x1+dx); + digitalWrite(_dc, 1); + SPI.transfer16(x2+dx); + digitalWrite(_dc, 0); + SPI.transfer(TFT_PASET); + digitalWrite(_dc, 1); + SPI.transfer16(y1+dy); + digitalWrite(_dc, 1); + SPI.transfer16(y2+dy); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + return; +} + +void T4_DSP::tft_setup(bool isST) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + // RESET if reset pin defined + if (_rst != 0xff) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + const uint8_t *addr = init_commands; + uint8_t count; + digitalWrite(_cs, 0); + while (count = *addr++) { + uint8_t command = *addr++; + if ( (command == TFT_INVON) && (!isST) ) { + // Skip TFT_INVON for ILI + } + else { + digitalWrite(_dc, 0); // command + SPI.transfer(command); + uint16_t ms = count & DELAY_MASK; + count &= ~DELAY_MASK; + while (--count > 0) { // data + uint8_t data = *addr++; + if ( (command == TFT_MADCTL) && (isST) ) { + data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; + } + digitalWrite(_dc, 1); + SPI.transfer(data); + } + if (ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + digitalWrite(_cs, 1); + SPI.endTransaction(); + delay(2); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + } + } + } + digitalWrite(_cs, 1); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + SPI.endTransaction(); + /* + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_dc, 0); + digitalWrite(_cs, 0); + SPI.transfer(TFT_MADCTL); + digitalWrite(_dc, 1); + SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); + // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); + digitalWrite(_cs, 1); + SPI.endTransaction(); + */ + cancelled = false; +} + +// display VGA image +gfx_error_t T4_DSP::begin(gfx_mode_t mode) +{ + uint32_t flexio_clock_div; + combine_shiftreg = 0; +// int div_select = 49; +// int num = 135; +// int denom = 100; + int div_select = 20; + int num = 9800; + int denom = 10000; + int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; + int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; + set_videoClock(div_select,num,denom,true); + +#ifdef DEBUG + Serial.println(mode); + Serial.println("mode"); +#endif + + switch(mode) + { + case MODE_TFTILI_320x240: +#ifdef DEBUG + Serial.println("TFTILI_320x240"); +#endif + tft_setup(false); + gfxmode = mode; + break; + case MODE_TFTST_320x240: +#ifdef DEBUG + Serial.println("TFTST_320x240"); +#endif + tft_setup(true); + gfxmode = mode; + break; + + case MODE_VGA_320x240: +#ifdef DEBUG + Serial.println("VGA_320x240"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_320x480: +#ifdef DEBUG + Serial.println("VGA_320x480"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_640x240: +#ifdef DEBUG + Serial.println("VGA_640x240"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/pix_freq; + line_double = 1; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_640x480: +#ifdef DEBUG + Serial.println("VGA_640x480"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = (flexio_freq/pix_freq); + line_double = 0; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_512x240: +#ifdef DEBUG + Serial.println("VGA_512x240"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 1; + pix_shift = 0; + break; + + case MODE_VGA_512x480: +#ifdef DEBUG + Serial.println("VGA_512x480"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 0; + pix_shift = 0; + break; + + case MODE_VGA_352x240: +#ifdef DEBUG + Serial.println("VGA_352x240"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_352x480: +#ifdef DEBUG + Serial.println("VGA_352x480"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + } + + if (mode >= MODE_VGA_320x240) + { + if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { + fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); + digitalWrite(_cs, 0); + digitalWrite(_dc, 0); + SPI.transfer(TFT_DISPOFF); + digitalWrite(_cs, 1); + delay(20); + digitalWrite(_cs, 0); + digitalWrite(_cs, 1); + } + gfxmode = mode; + + maxpixperline = vga_stride; + // Save param for tweek adjustment + ref_div_select = div_select; + ref_freq_num = num; + ref_freq_denom = denom; + ref_pix_shift = pix_shift; + +#ifdef DEBUG + Serial.println("frequency"); + Serial.println(flexio_freq); + Serial.println("div"); + Serial.println(flexio_freq/pix_freq); +#endif + + pinMode(_vsync_pin, OUTPUT); + pinMode(PIN_HBLANK, OUTPUT); + + /* Basic pin setup FlexIO1 */ + pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 + pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 + pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 + pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 + /* Basic pin setup FlexIO2 */ + pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 + pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 + pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 + pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 + + /* High speed and drive strength configuration */ + *(portControlRegister(PIN_G_B2)) = 0xFF; + *(portControlRegister(PIN_R_B0)) = 0xFF; + *(portControlRegister(PIN_R_B1)) = 0xFF; + *(portControlRegister(PIN_R_B2)) = 0xFF; + *(portControlRegister(PIN_B_B0)) = 0xFF; + *(portControlRegister(PIN_B_B1)) = 0xFF; + *(portControlRegister(PIN_G_B0)) = 0xFF; + *(portControlRegister(PIN_G_B1)) = 0xFF; + + /* Set clock for FlexIO1 and FlexIO2 */ + CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) + | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); + CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) + | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); + + + /* Set up pin mux FlexIO1 */ + *(portConfigRegister(PIN_G_B2)) = 0x14; + *(portConfigRegister(PIN_R_B0)) = 0x14; + *(portConfigRegister(PIN_R_B1)) = 0x14; + *(portConfigRegister(PIN_R_B2)) = 0x14; + /* Set up pin mux FlexIO2 */ + *(portConfigRegister(PIN_B_B0)) = 0x14; + *(portConfigRegister(PIN_B_B1)) = 0x14; + *(portConfigRegister(PIN_G_B0)) = 0x14; + *(portConfigRegister(PIN_G_B1)) = 0x14; + + /* Enable the clock */ + CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + /* Enable the FlexIO with fast access */ + FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + + uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; + uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; + + /* Shifter 0 registers for FlexIO2 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 + inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter + stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled + startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable + timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 + timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock + pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output + pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity + shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode + /* Shifter 0 registers for FlexIO1 */ + FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + /* Shifter 0 registers for FlexIO1 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 + FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + if (combine_shiftreg) { + pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled + FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + } + /* Timer 0 registers for FlexIO2 */ + timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset + timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output + timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset + timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare + timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert + stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled + startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled + if (combine_shiftreg) { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag + } + else { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag + } + triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low + triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected + pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled + //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 + //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high + timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode + // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) + + int shifts_per_transfer; + if (combine_shiftreg) { + shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 + } + else { + shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 + } + FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); + /* Timer 0 registers for FlexIO1 */ + FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); +#ifdef DEBUG + Serial.println("FlexIO setup complete"); +#endif + + /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ + if (combine_shiftreg) { + FLEXIO2_SHIFTSDEN |= (1<<1); + FLEXIO1_SHIFTSDEN |= (1<<1); + } + else { + FLEXIO2_SHIFTSDEN |= (1<<0); + FLEXIO1_SHIFTSDEN |= (1<<0); + } + /* Disable DMA channel so it doesn't start transferring yet */ + flexio1DMA.disable(); + flexio2DMA.disable(); + /* Set up DMA channel to use Shifter 0 trigger */ + flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); + flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); + + + if (combine_shiftreg) { + flexio2DMA.TCD->NBYTES = 8; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 8; + flexio2DMA.TCD->CITER = maxpixperline / 8; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + flexio1DMA.TCD->NBYTES = 8; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 8; + flexio1DMA.TCD->CITER = maxpixperline / 8; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Setup DMA2 Flexio2 copy + flexio2DMA.TCD->NBYTES = 4; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 4; + flexio2DMA.TCD->CITER = maxpixperline / 4; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + // Setup DMA1 Flexio1 copy + // Use pixel shift to avoid color smearing? + if (pix_shift & DMA_HACK) + { + if (pix_shift & 0x3 == 0) { + // Aligned 32 bits copy (32bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Unaligned (source) 32 bits copy (8bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 1; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion + } + } + else + { + // Aligned 32 bits copy + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + } + +#ifdef DEBUG + Serial.println("DMA setup complete"); +#endif + + // enable clocks for QTIMER3: generates the 15KHz for hsync + // Pulse: + // low : 3.8133 us => 569x6.7ns + // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) + // (OLD TEST) + // (4us low, 28us high => 32us) + // (597x6.7ns for 4us) + // (4179x6.7ns for 28us) + CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 + //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 + + #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz + #define MARGIN_D 1000 + + TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer + // Invert output pin as we want the interupt on rising edge + TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) + TMR3_CNTR3 = 0; + TMR3_LOAD3 = 0; + + /* Inverted timings */ + unsigned long long cpu_freq = F_CPU; + unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; + int rate2 = rate; + + int substract = 1; + if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { + substract=5; + rate2=1652; + } + + #ifdef DEBUG + Serial.print("MARGIN_N is: "); + Serial.println(rate2, DEC); + Serial.print("SUBSTRACT is: "); + Serial.println(substract, DEC); +#endif + TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; + TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; + /* + TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; + */ + TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on + TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), + // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) + //configure Teensy pin Compare output + IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 + attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function + NVIC_ENABLE_IRQ(IRQ_QTIMER3); +#ifdef DEBUG + Serial.println("QTIMER3 setup complete"); + Serial.print("V-PIN is "); + Serial.println(_vsync_pin); +#endif + + /* initialize gfx buffer */ + if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift + if (gfxbuffer == NULL) return(GFX_ERROR); +#ifdef DEBUG + Serial.println("Memory allocated"); +#endif + + memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); + vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; +#ifdef DEBUG + Serial.println(vga_stride); + Serial.println(vga_height); + Serial.println("Screen cleared"); +#endif + } + + return(GFX_OK); +} + +gfx_mode_t T4_DSP::getMode(void) +{ + return gfxmode; +} + +void T4_DSP::startRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + curTransfer = 0; + rstop = 0; + //dmatx.begin(true); + dmatx.attachInterrupt(TFT_isr); + setDmaStruct(); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + + digitalWrite(_cs, HIGH); + SPI.begin(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + + LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: + LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX + LPSPIP_TCR = 15; // Framesize 16 Bits + //LPSPIP_FCR = 0; // Fifo Watermark + LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable + LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: + dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); + + dmatx = dmasettings[0]; + digitalWrite(_cs, 0); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + dmatx.enable(); + } +} + + +void T4_DSP::stopRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + rstop = 1; + unsigned long m = millis(); + cancelled = true; + while (!rstop) { + if ((millis() - m) > 100) break; + delay(10); + asm volatile("wfi"); + }; + rstop = 0; + delay(50); + cancelled = false; + dmatx.detachInterrupt(); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + SPI.end(); +#ifdef ST7789 +// begin(gfxmode); +#endif + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + } +} + +int T4_DSP::get_frame_buffer_size(int *width, int *height) { + if (gfxmode < MODE_VGA_320x240) { + if (width != nullptr) *width = tft_width; + if (height != nullptr) *height = tft_height; + return tft_stride; + } + else { + if (width != nullptr) *width = vga_width; + if (height != nullptr) *height = vga_height; + return vga_stride; + } +} + +void T4_DSP::waitSync() +{ + if (gfxmode >= MODE_VGA_320x240) { + while (VSYNC == 0) {}; + } +} + +void T4_DSP::waitLine(int line) +{ + if (gfxmode >= MODE_VGA_320x240) { + while (currentLine != line) {}; + } +} + +/*********************************************************************************************** + No DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreenNoDma(uint16_t color) { + if (gfxmode < MODE_VGA_320x240) { + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + int i,j; + for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(arx, ary, arx+arw-1, ary+arh-1); + bitmap = bitmap + bmp_offy*w + bmp_offx; + for (int row=0;row> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + bits = *charpt++; + //digitalWrite(_dc, 1); + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + x +=8; + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + else { + drawText(x, y, text, fgcolor, bgcolor, doublesize); + } +} + + +/*********************************************************************************************** + DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreen(uint16_t color) { + int i,j; + if (gfxmode < MODE_VGA_320x240) { + for (j=0; j> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + dst=&tft_buffer[l*tft_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + x +=8; + } + } + else { + vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); + vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); + vga_pixel * dst; + while ((c = *text++)) { + const unsigned char * charpt=&font8x8[c][0]; + int l=y; + for (int i=0;i<8;i++) + { + unsigned char bits; + if (doublesize) { + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + x +=8; + } + } +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { + drawSprite(x,y,bitmap, 0,0,0,0); +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) +{ + int bmp_offx = 0; + int bmp_offy = 0; + uint16_t *bmp_ptr; + int w =*bitmap++; + int h = *bitmap++; + if ( (arw == 0) || (arh == 0) ) { + // no crop window + arx = x; + ary = y; + arw = w; + arh = h; + } + else { + if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + int l=ary; + bitmap = bitmap + bmp_offy*w + bmp_offx; + + if (gfxmode < MODE_VGA_320x240) { + for (int row=0;row tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]; + pos +=step; + } + #endif + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i 2) ) y += (tft_height-height)/2; + uint16_t * dst=&tft_buffer[y*tft_stride]; + if (width > tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]]; + pos +=step; + } +#endif + } + else if ((width*2) == tft_width) { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]]; + *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i tft_width) { + int step = ((width << 8)/tft_width); + int pos = 0; + for (int i=0; i> 8]]; + pos +=step; + } + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = pix; + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i +#include +#endif + +#include "platform_config.h" +#include "iopins.h" + + + +#ifndef TFT_WIDTH +#define TFT_WIDTH 320 +#endif +#define TFT_REALWIDTH 320 + +#ifndef TFT_HEIGHT +#define TFT_HEIGHT 240 +#endif +#define TFT_REALHEIGHT 240 + + +typedef enum gfx_mode_t +{ + MODE_UNDEFINED = 0, + MODE_TFTILI_320x240 = 1, + MODE_TFTST_320x240 = 2, + MODE_VGA_320x240 = 3, + MODE_VGA_320x480 = 4, + MODE_VGA_352x240 = 5, + MODE_VGA_352x480 = 6, + MODE_VGA_512x240 = 7, + MODE_VGA_512x480 = 8, + MODE_VGA_640x240 = 9, + MODE_VGA_640x480 = 10 +} gfx_mode_t; + +typedef enum gfx_error_t +{ + GFX_OK = 0, + GFX_ERROR = -1 +} gfx_error_t; + + +#ifdef __cplusplus + +class T4_DSP +{ + public: + T4_DSP(); + + gfx_error_t begin(gfx_mode_t mode); + gfx_mode_t getMode(void); + void startRefresh(void); + void stopRefresh(); + + int get_frame_buffer_size(int *width, int *height); + void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); + + // wait next Vsync + void waitSync(); + void waitLine(int line); + + // NoDMA functions + void fillScreenNoDma(uint16_t color); + void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + // DMA functions + void fillScreen(uint16_t color); + void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + void writeLine(int width, int height, int y, uint16_t *buf); + void writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + void writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16); + void writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + + protected: + static uint8_t _rst, _cs, _dc; + static uint8_t _mosi, _sclk; + static uint8_t _vsync_pin; + static DMAChannel flexio1DMA; + static DMAChannel flexio2DMA; + void tft_setup(bool isST); + static void TFT_isr(void); + static void QT3_isr(void); +}; + +#endif +#endif diff --git a/MCUME_teensy41/teensysms/teensysms.ino b/MCUME_teensy41/teensysms/teensysms.ino index 78af83d..6432f02 100644 --- a/MCUME_teensy41/teensysms/teensysms.ino +++ b/MCUME_teensy41/teensysms/teensysms.ino @@ -2,132 +2,20 @@ extern "C" { #include "iopins.h" #include "emuapi.h" } - -#include "emu.h" -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -TFT_T_DMA tft; -#else -#include "tft_t_dma.h" -TFT_T_DMA tft = TFT_T_DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, TFT_TOUCH_CS, TFT_TOUCH_INT); -#endif - -bool vgaMode = false; - -static unsigned char palette8[PALETTE_SIZE]; -static unsigned short palette16[PALETTE_SIZE]; -static IntervalTimer myTimer; -volatile boolean vbl=true; -static int skip=0; -static elapsedMicros tius; - -static void vblCount() { - if (vbl) { - vbl = false; - } else { - vbl = true; - } -} - -void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) -{ - if (index>8, - 320 & 0xFF, // YEND = 320 - ST7735_INVON , DELAY, // 7: hack - 10, - ST7735_NORON , DELAY, // 8: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 9: Main screen turn on, no args, w/delay - 255 -#endif -}; - -static void dmaInterrupt() { - dmatx.clearInterrupt(); - curTransfer++; - if (curTransfer >= nbTransfer) { - curTransfer = 0; - if (cancelled) { - dmatx.disable(); - rstop = 1; - } - } - arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2); -} - -static void setDmaStruct() { - uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; - int i=0; - uint16_t col=RGBVAL16(0x00,0x00,0x00);; - while (remaining > 0) { - uint16_t * fb = blocks[i]; - int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining); -#ifdef TFT_DEBUG - Serial.println((unsigned long)blocks[i]); - Serial.println(remaining); -#endif - switch (i) { - case 0: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb0[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0x00); -#endif - break; - case 1: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb1[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0xff); -#endif - break; - case 2: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb2[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0x00,0xff); -#endif - break; - case 3: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb3[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0xff,0x00,0xff); -#endif - break; - } - blocks[i] = fb; - if (blocks[i] == 0) { - Serial.print("ILI9341 allocaltion failed for block "); - Serial.println(i); - delay(10000); - } - - for (int j=0;jATTR_DST = 1; - dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); - dmasettings[i].interruptAtCompletion(); - remaining -= len; - i++; - } - dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); - nbTransfer = i; -#ifdef TFT_DEBUG - Serial.println(nbTransfer); -#endif -} - - -TFT_T_DMA::TFT_T_DMA(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso, uint8_t touch_cs, uint8_t touch_irq) -{ - _cs = cs; - _dc = dc; - _rst = rst; - _mosi = mosi; - _sclk = sclk; - _miso = miso; - pinMode(_dc, OUTPUT); - pinMode(_cs, OUTPUT); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); - if ( (touch_cs != 255) && (touch_irq != 255) ) { - _touch_irq = touch_irq; - _touch_cs = touch_cs; - pinMode(_touch_cs, OUTPUT); - pinMode(touch_irq, INPUT_PULLUP); - digitalWrite(_touch_cs, 1); - } -} - - -void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { - int dx=0; - int dy=0; -#ifdef ST7789 - if (TFT_REALWIDTH == TFT_REALHEIGHT) - { -#ifdef ROTATE_SCREEN - if (!flipped) { - dy += 80; - } -#else - if (flipped) { - dx += 80; - } -#endif - } -#endif - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - SPI.transfer16(x1+dx); - digitalWrite(_dc, 1); - SPI.transfer16(x2+dx); - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - digitalWrite(_dc, 1); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - return; - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - - SPI.transfer16(x1+dx); - SPI.transfer16(x2+dx); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - -void TFT_T_DMA::begin(void) { - SPI.setMOSI(_mosi); - SPI.setMISO(_miso); - SPI.setSCK(_sclk); - SPI.begin(); - - // Initialize display - if (_rst != 0xff) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - const uint8_t *addr = init_commands; - digitalWrite(_cs, 0); -#ifdef ILI9341 - while (1) { - uint8_t count = *addr++; - if (count-- == 0) break; - - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - - while (count-- > 0) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - } - - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(ILI9341_DISPON); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); -#endif -#ifdef ST7789 - uint8_t numCommands, numArgs; - uint16_t ms; - numCommands = *addr++; // Number of commands to follow - while(numCommands--) { // For each command... - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - numArgs = *addr++; // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs > 1) { // For each argument... - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - numArgs--; - } - - if (numArgs) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - if(ms) { - ms = *addr++; // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - digitalWrite(_cs, 1); - SPI.endTransaction(); - delay(ms); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - } - } - digitalWrite(_cs, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - SPI.endTransaction(); - - cancelled = false; - -#ifdef FLIP_SCREEN - flipscreen(true); -#else - flipscreen(false); -#endif -#ifdef ST7789 - if (TFT_REALWIDTH != TFT_REALHEIGHT) - { - flipscreen(true); - } -#endif -}; - - - -void TFT_T_DMA::flipscreen(bool flip) -{ - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(TFT_MADCTL); - digitalWrite(_dc, 1); - if (flip) { - flipped=true; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB); -#endif -#endif - } - else { - flipped=false; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB); -#endif -#endif - } - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - -boolean TFT_T_DMA::isflipped(void) -{ - return(flipped); -} - - -#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) - - -void TFT_T_DMA::startDMA(void) { - curTransfer = 0; - rstop = 0; - //dmatx.begin(true); - dmatx.attachInterrupt(dmaInterrupt); - setDmaStruct(); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - - digitalWrite(_cs, HIGH); - SPI.begin(); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); - - - LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: - LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX - LPSPIP_TCR = 15; // Framesize 16 Bits - //LPSPIP_FCR = 0; // Fifo Watermark - LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable - LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: - dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); - - dmatx = dmasettings[0]; - digitalWrite(_cs, 0); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - dmatx.enable(); -} - - -void TFT_T_DMA::stopDMA(void) { - rstop = 0; - wait(); - delay(50); - cancelled = false; - dmatx.detachInterrupt(); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - SPI.end(); -#ifdef ST7789 - begin(); -#endif -#ifdef ILI9341 - SPI.begin(); - digitalWrite(_cs, 0); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - SPI.endTransaction(); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); -} - -void TFT_T_DMA::wait(void) { - rstop = 1; - unsigned long m = millis(); - cancelled = true; - while (!rstop) { - if ((millis() - m) > 100) break; - delay(10); - asm volatile("wfi"); - }; - rstop = 0; -} - -int TFT_T_DMA::get_frame_buffer_size(int *width, int *height){ - if (width != nullptr) *width = TFT_REALWIDTH; - if (height != nullptr) *height = TFT_REALHEIGHT; - return TFT_REALWIDTH; -} - - -/*********************************************************************************************** - Touch functions - ***********************************************************************************************/ -/* Code based on ... - * - * @file XPT2046.cpp - * @date 19.02.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the XPT2046 driver for Arduino. - */ - -#define ADC_MAX 0x0fff - -void TFT_T_DMA::enableTouchIrq() -{ - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 }; - SPI.transfer((void*)&buf[0],3); - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); -} - -//Default callibration for non flipped -#define TX_MIN 30 -#define TY_MIN 20 -#define TX_MAX 300 -#define TY_MAX 220 - -//Default callibration for flipped -#define TFX_MIN 20 -#define TFY_MIN 25 -#define TFX_MAX 288 -#define TFY_MAX 221 - -static uint16_t txMin; -static uint16_t tyMin; -static uint16_t txMax; -static uint16_t tyMax; - - -void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { - if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) { - txMin = xMin; - tyMin = yMin; - txMax = xMax; - tyMax = yMax; - } - else { - if (flipped) { - txMin = TFX_MIN; - tyMin = TFY_MIN; - txMax = TFX_MAX; - tyMax = TFY_MAX; - } - else { - txMin = TX_MIN; - tyMin = TY_MIN; - txMax = TX_MAX; - tyMax = TY_MAX; - } - } -} - - -void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - if ( TOUCH_ENABLED() ) { - uint16_t x = 0; - uint16_t y = 0; - uint16_t z1 = 0; - uint16_t z2 = 0; - uint8_t i = 0; - int16_t xraw=0, yraw=0; - - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - - for(; i < 15; i++) { - // SPI requirer 32bit aliment - uint8_t buf[12] = { - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00 - }; - SPI.transfer(&buf[0], &buf[0], 12); - y += (buf[1] << 8 | buf[2])>>3; - x += (buf[4] << 8 | buf[5])>>3; - z1 += (buf[7] << 8 | buf[8])>>3; - z2 += (buf[10] << 8 | buf[11])>>3; - } - enableTouchIrq(); - - if(i == 0) { - *oX = 0; - *oY = 0; - *oZ = 0; - } - else { - x /= i; - y /= i; - z1 /= i; - z2 /= i; - } - - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); - int z = z1 + ADC_MAX - z2; - if (flipped) { - xraw = x; - yraw = y; - } else { - xraw = ADC_MAX - x; - yraw = ADC_MAX - y; - } - xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1); - yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1); - - *oX = xraw; - *oY = yraw; - *oZ = z; - } - else - { - *oX = 0; - *oY = 0; - *oZ = 0; - } -} - -void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - readRaw(oX,oY,oZ); - // callibrate ... - if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin); - if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin); - //Serial.print(*oX); - //Serial.print(" "); - //Serial.println(*oY); -} - - -/*********************************************************************************************** - No DMA functions - ***********************************************************************************************/ -void TFT_T_DMA::fillScreenNoDma(uint16_t color) { - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - int i,j; - for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(arx, ary, arx+arw-1, ary+arh-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - bits = *charpt++; - //digitalWrite(_dc, 1); - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - x +=8; -#ifdef ILI9341 - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); -#endif - digitalWrite(_cs, 1); - SPI.endTransaction(); - } - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - - - -/*********************************************************************************************** - DMA functions - ***********************************************************************************************/ -uint16_t * TFT_T_DMA::getLineBuffer(int j) -{ - uint16_t * block=blocks[j>>6]; - return(&block[(j&0x3F)*TFT_REALWIDTH]); -} - -void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) { - uint8_t *buffer=buf; - uint8_t *src; - - int i,j,y=0; - if (width*2 <= TFT_REALWIDTH) { - for (j=0; j>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH]; - for (i=0; i>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x]; - for (i=0; i>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - block=blocks[l>>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt++; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - x +=8; - } -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { - drawSprite(x,y,bitmap, 0,0,0,0); -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) -{ - int bmp_offx = 0; - int bmp_offy = 0; - uint16_t *bmp_ptr; - - int w =*bitmap++; - int h = *bitmap++; - - - if ( (arw == 0) || (arh == 0) ) { - // no crop window - arx = x; - ary = y; - arw = w; - arh = h; - } - else { - if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - int l=ary; - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx]; - bmp_ptr = (uint16_t*)bitmap; - for (int col=0;col -#include -#include -#endif - -#include "tft_t_dma_config.h" - -#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) -#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define R16(rgb) ((rgb>>8)&0xf8) -#define G16(rgb) ((rgb>>3)&0xfc) -#define B16(rgb) ((rgb<<3)&0xf8) - -#define PAL_COLOR_MASK 0xff - -#ifdef LOHRES -#define TFT_WIDTH 240 -#define TFT_REALWIDTH 240 -#else -#define TFT_WIDTH 256 -#define TFT_REALWIDTH 320 -#endif -#define TFT_HEIGHT 192 -#define TFT_REALHEIGHT 240 - -//#define WIDTH 272 -//#define HEIGHT 228 - -#define LINES_PER_BLOCK 64 -#define NR_OF_BLOCK 4 -#define SCREEN_DMA_NUM_SETTINGS NR_OF_BLOCK - - -#ifdef ILI9341 - -#define ILI9341_NOP 0x00 -#define ILI9341_SWRESET 0x01 -#define ILI9341_RDDID 0x04 -#define ILI9341_RDDST 0x09 - -#define ILI9341_SLPIN 0x10 -#define ILI9341_SLPOUT 0x11 -#define ILI9341_PTLON 0x12 -#define ILI9341_NORON 0x13 - -#define ILI9341_RDMODE 0x0A -#define ILI9341_RDMADCTL 0x0B -#define ILI9341_RDPIXFMT 0x0C -#define ILI9341_RDIMGFMT 0x0D -#define ILI9341_RDSELFDIAG 0x0F - -#define ILI9341_INVOFF 0x20 -#define ILI9341_INVON 0x21 -#define ILI9341_GAMMASET 0x26 -#define ILI9341_DISPOFF 0x28 -#define ILI9341_DISPON 0x29 - -#define ILI9341_CASET 0x2A -#define ILI9341_PASET 0x2B -#define ILI9341_RAMWR 0x2C -#define ILI9341_RAMRD 0x2E - -#define ILI9341_PTLAR 0x30 -#define ILI9341_MADCTL 0x36 -#define ILI9341_VSCRSADD 0x37 -#define ILI9341_PIXFMT 0x3A - -#define ILI9341_FRMCTR1 0xB1 -#define ILI9341_FRMCTR2 0xB2 -#define ILI9341_FRMCTR3 0xB3 -#define ILI9341_INVCTR 0xB4 -#define ILI9341_DFUNCTR 0xB6 - -#define ILI9341_PWCTR1 0xC0 -#define ILI9341_PWCTR2 0xC1 -#define ILI9341_PWCTR3 0xC2 -#define ILI9341_PWCTR4 0xC3 -#define ILI9341_PWCTR5 0xC4 -#define ILI9341_VMCTR1 0xC5 -#define ILI9341_VMCTR2 0xC7 - -#define ILI9341_RDID1 0xDA -#define ILI9341_RDID2 0xDB -#define ILI9341_RDID3 0xDC -#define ILI9341_RDID4 0xDD - -#define ILI9341_GMCTRP1 0xE0 -#define ILI9341_GMCTRN1 0xE1 - -#define ILI9341_MADCTL_MY 0x80 -#define ILI9341_MADCTL_MX 0x40 -#define ILI9341_MADCTL_MV 0x20 -#define ILI9341_MADCTL_ML 0x10 -#define ILI9341_MADCTL_RGB 0x00 -#define ILI9341_MADCTL_BGR 0x08 -#define ILI9341_MADCTL_MH 0x04 - -#define TFT_CASET ILI9341_CASET -#define TFT_PASET ILI9341_PASET -#define TFT_RAMWR ILI9341_RAMWR -#define TFT_MADCTL ILI9341_MADCTL - -#endif - - -#ifdef ST7789 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_RGB 0x00 -#define ST77XX_MADCTL_BGR 0x08 -#define ST77XX_MADCTL_MH 0x04 - -#define TFT_CASET ST7735_CASET -#define TFT_PASET ST7735_RASET -#define TFT_RAMWR ST7735_RAMWR -#define TFT_MADCTL ST7735_MADCTL - -#endif - - - -#ifdef __cplusplus - -class TFT_T_DMA -{ - public: - TFT_T_DMA(uint8_t _CS, uint8_t _DC, uint8_t _RST = 255, uint8_t _MOSI=11, uint8_t _SCLK=13, uint8_t _MISO=12, uint8_t touch_cs=38, uint8_t touch_irq=37); - - void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); - void begin(void); - void flipscreen(bool flip); - boolean isflipped(void); - void startDMA(void); - void stopDMA(); - int get_frame_buffer_size(int *width, int *height); - - // Touch screen functions - #define TOUCH_ENABLED() ((_touch_cs != 255) && (_touch_irq != 255)) - bool isTouching(void) { return ((!TOUCH_ENABLED())?false:(digitalRead(_touch_irq) == LOW)); } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax); - - // NoDMA functions - void writeScreenNoDma(const uint16_t *pcolors); - void fillScreenNoDma(uint16_t color); - void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - // DMA functions - uint16_t * getLineBuffer(int j); - void writeScreen(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int y, uint16_t *buf); - void fillScreen(uint16_t color); - void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - protected: - uint8_t _rst, _cs, _dc; - uint8_t _miso, _mosi, _sclk; - uint8_t _touch_irq=255, _touch_cs=255; - bool flipped=false; - - void wait(void); - void enableTouchIrq(); -}; - -#endif -#endif diff --git a/MCUME_teensy41/teensysms/tft_t_dma_config.h b/MCUME_teensy41/teensysms/tft_t_dma_config.h deleted file mode 100644 index 0a712da..0000000 --- a/MCUME_teensy41/teensysms/tft_t_dma_config.h +++ /dev/null @@ -1,13 +0,0 @@ -#include "platform_config.h" - -//#define ST7789 1 -//#define ILI9341 1 - -#define TFT_LINEARINT 1 -#define LINEARINT_HACK 1 - -//#define FLIP_SCREEN 1 -//#define TFT_DEBUG 1 -#if defined(__IMXRT1052__) || defined(__IMXRT1062__) -//#define TFT_STATICFB 1 -#endif diff --git a/MCUME_teensy41/teensysms/vga_t_dma.h b/MCUME_teensy41/teensysms/vga_t_dma.h deleted file mode 100644 index 81a986b..0000000 --- a/MCUME_teensy41/teensysms/vga_t_dma.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - Wrapping class to extend VGA_T4 to TFT_T_DMA -*/ - -#ifndef _VGA_T_DMAH_ -#define _VGA_T_DMAH_ - -#ifdef __cplusplus -#include -#endif - - -#define RGBVAL16(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) - - - - -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 - -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - - - -#ifdef __cplusplus - -class TFT_T_DMA: public VGA_T4 -{ - public: - // Fake touch screen functions - bool isTouching(void) { return false; } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { } - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { }; - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { } - - // fake DMA functions - void startDMA(void) { }; - void stopDMA(void) { }; - - // fake no DMA functions - void writeScreenNoDma(const vga_pixel *pcolors) { writeScreen(pcolors); } - void fillScreenNoDma(vga_pixel color) { clear(color); } - void drawTextNoDma(int16_t x, int16_t y, const char * text, vga_pixel fgcolor, vga_pixel bgcolor, bool doublesize) { drawText(x,y,text,fgcolor,bgcolor,doublesize); } - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, vga_pixel color) { drawRect(x, y, w, h, color); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap) { drawSprite(x, y, bitmap); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh) { drawSprite(x, y, bitmap, croparx, cropary, croparw, croparh); } -}; - - -#endif -#endif diff --git a/MCUME_teensy41/teensysms/emu.cpp b/MCUME_teensy41/teensysms/wrapemu.cpp similarity index 90% rename from MCUME_teensy41/teensysms/emu.cpp rename to MCUME_teensy41/teensysms/wrapemu.cpp index 839473b..d599c2f 100644 --- a/MCUME_teensy41/teensysms/emu.cpp +++ b/MCUME_teensy41/teensysms/wrapemu.cpp @@ -1,7 +1,6 @@ #include #include "emuapi.h" -#include "tft_t_dma.h" #include "iopins.h" extern "C" { @@ -11,7 +10,7 @@ extern "C" { static int rom_offset = 0; -EXTMEM static unsigned char MemPool[8*1024*1024]; +static unsigned char * MemPool; extern "C" uint8 read_rom(int address) { return (MemPool[address+rom_offset]); @@ -51,6 +50,7 @@ void emu_KeyboardOnUp(int keymodifer, int key) { void sms_Init(void) { emu_printf("Allocating MEM"); + MemPool = emu_SMalloc(8*1024*1024); mem_init(); emu_printf("Allocating MEM done"); } @@ -105,17 +105,11 @@ void sms_Start(char * filename) } } - #ifdef HAS_SND -#ifdef SOUND_PRESENT system_init(22050); - emu_sndInit(); #else system_init(0); #endif -#else - system_init(0); -#endif emu_printf("init done"); } @@ -139,15 +133,15 @@ void sms_Step(void) if (( k & MASK_JOY1_DOWN) || ( k & MASK_JOY2_DOWN)) { input.pad[0] |= INPUT_DOWN; } - if ( k & MASK_JOY2_BTN) { + if (( k & MASK_JOY1_BTN) || ( k & MASK_JOY2_BTN)) { input.pad[0] |= INPUT_BUTTON1; } - if ( (k & MASK_KEY_USER1) || (hk == 'q') ) { + if ( (k & MASK_KEY_USER2) || (hk == 'q') ) { input.pad[0] |= INPUT_BUTTON2; } - if ( (k & MASK_KEY_USER2) || (hk == 'w') ) input.system |= (IS_GG) ? INPUT_START : INPUT_PAUSE; + if ( (k & MASK_KEY_USER1) || (hk == 'w') ) input.system |= (IS_GG) ? INPUT_START : INPUT_PAUSE; if (hk == 'r') input.system |= INPUT_HARD_RESET; //if (hk == 'e') input.system |= (IS_GG) ? INPUT_HARD_RESET : INPUT_SOFT_RESET; @@ -160,9 +154,7 @@ void sms_Step(void) } void SND_Process(void *stream, int len) { -#ifdef SOUND_PRESENT #ifdef HAS_SND audio_play_sample(stream, 0, len); -#endif -#endif +#endif } diff --git a/MCUME_teensy41/teensysms/emu.h b/MCUME_teensy41/teensysms/wrapemu.h similarity index 65% rename from MCUME_teensy41/teensysms/emu.h rename to MCUME_teensy41/teensysms/wrapemu.h index c546f70..972e6c4 100644 --- a/MCUME_teensy41/teensysms/emu.h +++ b/MCUME_teensy41/teensysms/wrapemu.h @@ -1,4 +1,10 @@ +#ifdef __cplusplus +extern "C" { +#endif extern void sms_Init(void); extern void sms_Step(void); extern void sms_Start(char * filename); extern void sms_Input(int click); +#ifdef __cplusplus +} +#endif diff --git a/MCUME_teensy41/teensysnes/emuapi.cpp b/MCUME_teensy41/teensysnes/emuapi.cpp index 8c78278..e128cca 100644 --- a/MCUME_teensy41/teensysnes/emuapi.cpp +++ b/MCUME_teensy41/teensysnes/emuapi.cpp @@ -5,11 +5,7 @@ extern "C" { #include "iopins.h" } -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#else -#include "tft_t_dma.h" -#endif +#include #ifdef HAS_USB #include "USBHost_t36.h" // Read this header first for key info @@ -32,6 +28,8 @@ JoystickController joysticks[COUNT_JOYSTICKS](myusb); static bool emu_writeConfig(void); static bool emu_readConfig(void); static bool emu_eraseConfig(void); +static bool emu_writeGfxConfig(char * display_type); +static int emu_readGfxConfig(void); static bool mouseDetected = false; static bool keyboardDetected = false; @@ -42,6 +40,7 @@ static File file; #define MAX_FILES 64 #define AUTORUN_FILENAME "autorun.txt" +#define GFX_CFG_FILENAME "gfxmode.txt" #define MAX_FILENAME_SIZE 34 #define MAX_MENULINES 9 @@ -61,7 +60,8 @@ static File file; #define MENU_VGA_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) #define MENU_VGA_YOFFSET (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37) -extern TFT_T_DMA tft; +#include "t4_dsp.h" +T4_DSP tft; static int nbFiles=0; static int curFile=0; @@ -73,6 +73,8 @@ static char selected_filename[MAX_FILENAME_SIZE]=""; static char second_selected_filename[MAX_FILENAME_SIZE]=""; static bool menuRedraw=true; static bool autorun=false; +static bool vgahires=false; + static const unsigned short * keys; #ifdef TEECOMPUTER @@ -360,9 +362,10 @@ int emu_ReadKeys(void) #endif if ( row & 0x02 ) retval |= MASK_JOY2_BTN; + #ifdef EXTPAD - if ( fn_pressed ) retval |= MASK_KEY_USER1; if ( sh_pressed ) retval |= MASK_KEY_USER3; + if ( fn_pressed ) retval |= MASK_KEY_USER1; digitalWrite(KLED, 0); #else // Handle LED flash @@ -646,7 +649,7 @@ int emu_setKeymap(int index) { } int emu_GetMouse(int *x, int *y, int *buts) { -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBKEY) if (mouse1.available()) { *buts = mouse1.getButtons(); *x = mouse1.getMouseX(); @@ -660,7 +663,7 @@ int emu_GetMouse(int *x, int *y, int *buts) { } int emu_GetJoystick(void) { -#ifdef HAS_USBJOY +#if defined(HAS_USB) && (HAS_USBJOY) for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) { if (joysticks[joystick_index].available()) { uint64_t axis_mask = joysticks[joystick_index].axisMask(); @@ -675,7 +678,7 @@ int emu_GetJoystick(void) { return 0; } -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBKEY) void OnPress(auto key) { keyboardDetected = true; @@ -819,7 +822,7 @@ int emu_KeyboardDetected(void) { return (keyboardDetected?1:0); } -#ifdef HAS_USBMIDI +#if defined(HAS_USB) && (HAS_USBMIDI) static unsigned char midiBuffer[16]; static unsigned char midiLastCmd=0; static int midiDataCnt=0; @@ -827,7 +830,7 @@ static int midiCmdNbParam=0; #endif void emu_MidiOnDataReceived(unsigned char value) { -#ifdef HAS_USBMIDI +#if defined(HAS_USB) && (HAS_USBMIDI) //Serial.println(value, HEX); //10000000 = 128 = note off //10010000 = 144 = note on @@ -995,6 +998,7 @@ void emu_MidiOnDataReceived(unsigned char value) { /******************************** * Menu file loader UI ********************************/ +#ifdef FILEBROWSER static int readNbFiles(void) { int totalFiles = 0; @@ -1024,8 +1028,6 @@ static int readNbFiles(void) { return totalFiles; } - - void backgroundMenu(void) { menuRedraw=true; tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00)); @@ -1035,11 +1037,13 @@ void backgroundMenu(void) { int handleMenu(uint16_t bClick) { if (autorun) { + toggleMenu(false); + menuRedraw=false; return (ACTION_RUN1); } int action = ACTION_NONE; - if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) ) { + if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) || ( bClick & MASK_KEY_USER2 ) ) { char newpath[MAX_FILENAME_PATH]; strcpy(newpath, selection); strcat(newpath, "/"); @@ -1050,17 +1054,31 @@ int handleMenu(uint16_t bClick) File file = SD.open(selection); if (file.isDirectory()) { curFile = 0; - nbFiles = readNbFiles(); + nbFiles = readNbFiles(); + menuRedraw=true; } - else { - action = ACTION_RUN1; + else + { #ifdef TEECOMPUTER - if (key_extmode) { + if ( (key_extmode) || ( key_sh) ) { emu_writeConfig(); } + if ( tft.getMode() < MODE_VGA_320x240) { + if ( bClick & MASK_KEY_USER2 ) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + } + //emu_SwapJoysticks(0); #endif + toggleMenu(false); + menuRedraw=false; + return (ACTION_RUN1); } - menuRedraw=true; } else if ( bClick & MASK_KEY_USER1 ) { menuRedraw=true; @@ -1069,19 +1087,14 @@ int handleMenu(uint16_t bClick) strcat(second_selection, "/"); strcat(second_selection, second_selected_filename); action = ACTION_RUN2; - } - else if ( bClick & MASK_KEY_USER2 ) { - menuRedraw=true; - //action = ACTION_RUN3; - emu_SwapJoysticks(0); - } + } else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) { if (curFile!=0) { menuRedraw=true; curFile--; } } - else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { + else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { if ((curFile-9)>=0) { menuRedraw=true; curFile -= 9; @@ -1096,7 +1109,7 @@ int handleMenu(uint16_t bClick) menuRedraw=true; } } - else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { + else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { if ((curFile<(nbFiles-9)) && (nbFiles)) { curFile += 9; menuRedraw=true; @@ -1153,12 +1166,12 @@ int handleMenu(uint16_t bClick) return (action); } -bool menuActive(void) +int menuActive(void) { - return (menuOn); + return (menuOn?1:0); } -void toggleMenu(bool on) { +void toggleMenu(int on) { if (on) { menuOn=true; backgroundMenu(); @@ -1176,7 +1189,7 @@ char * menuSecondSelection(void) { return (second_selection); } - +#endif /******************************** * OSKB handling @@ -1196,7 +1209,7 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) int i=0; int fb_width,fb_height,fbstride; - tft.get_frame_buffer_size(&fb_width, &fb_height, &fbstride); + fbstride = tft.get_frame_buffer_size(&fb_width, &fb_height); int ypos = (bottom?(fb_height-2*8):0); int line = row + (bottom?2:0); while ((c[1] = *cpt++)) @@ -1205,7 +1218,7 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0); else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff); if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff); - tft.drawTextNoDma(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); + tft.drawText(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); i++; } } @@ -1303,7 +1316,7 @@ int handleOSKB(void) { return retval; } -void toggleOSKB(bool forceon) { +void toggleOSKB(int forceon) { if (forceon) { oskbOn = true; drawOSKB(); @@ -1387,6 +1400,17 @@ int emu_FileRead(void * buf, int size, int handler) #endif } +int emu_FileWrite(void * buf, int size, int handler) +{ +// emu_printf("emu_FileWrite"); +// emu_printi(handler); +#ifdef HCFH + return (file.write(buf, size)); +#else + return (getFileHandler(handler).write(buf, size)); +#endif +} + int emu_FileGetc(int handler) { // emu_printf("FileGetc"); // emu_printi(handler); @@ -1547,6 +1571,48 @@ static bool emu_eraseConfig(void) SD.remove (ROMSDIR "/" AUTORUN_FILENAME); } +static bool emu_writeGfxConfig(char * display_type) +{ + bool retval = false; + SD.remove ("/" GFX_CFG_FILENAME); + if (strcmp(display_type, "VGA")) { + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(display_type, strlen(display_type)) != strlen(display_type)) { + emu_printf("GFX config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + } + return retval; +} + +#define CFG_VGA 0 +#define CFG_ILI 1 +#define CFG_ST 2 + +static int emu_readGfxConfig(void) +{ + int retval = CFG_VGA; // No file = VGA + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + if (filesize == 2) // "ST" + { + retval = CFG_ST; + } + else if (filesize == 3) // "ILI" + { + retval = CFG_ILI; + } + lofile.close(); + } + return retval; +} + /******************************** * File IO compatibility ********************************/ @@ -1728,11 +1794,137 @@ FRESULT f_mkdir (const char* path) /******************************** - * Initialization + * GFX wrapper ********************************/ -void emu_init(void) +static unsigned short palette16[PALETTE_SIZE]; +static IntervalTimer myTimer; +volatile boolean vbl=true; +volatile boolean vgatimervsync=false; +static void (*vblCallback)(void) = nullptr; +static int skip=0; + +static void vblCount() { + if (vbl) { + vbl = false; + } else { + vbl = true; + } +} + +void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) +{ + if (index= MODE_VGA_320x240 ) { + if (vgatimervsync) { + while (vbl==vb) {}; + } + else { + tft.waitSync(); + } + } + else { + while (vbl==vb) {}; + } + if (vblCallback != nullptr) { + vblCallback(); + } +} + +void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride) +{ + if (skip == 0) { + tft.writeScreenPal(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); + } +} +void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLinePal(width,height,line, VBuf, palette16); + } +} + +void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine(width,height,line, VBuf); + } +} + +void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine8(width,height,line, VBuf, palette16); + } +} + +int emu_IsVga(void) +{ + return (tft.getMode() >= MODE_VGA_320x240?1:0); +} + +int emu_IsVgaHires(void) +{ + return (tft.getMode() >= MODE_VGA_640x240?1:0); +} + +int emu_FrameSkip(void) +{ + return skip; +} + + +/******************************** + * AUDIO wrapper +********************************/ +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +AudioPlaySystem mymixer; + +void emu_sndInit() { + Serial.println("sound init"); + mymixer.begin_audio(256, mymixer.snd_Mixer); + mymixer.start(); +} + +void emu_sndPlaySound(int chan, int volume, int freq) +{ + if (chan < 6) { + mymixer.sound(chan, freq, volume); + } + /* + Serial.print(chan); + Serial.print(":" ); + Serial.print(volume); + Serial.print(":" ); + Serial.println(freq); + */ +} + +void emu_sndPlayBuzz(int size, int val) { + mymixer.buzz(size,val); + //Serial.print((val==1)?1:0); + //Serial.print(":"); + //Serial.println(size); +} +#endif + +/******************************** + * Initialization +********************************/ +void emu_init(int hires) { Serial.begin(115200); + vgahires = hires; #ifdef HAS_USB myusb.begin(); @@ -1742,50 +1934,109 @@ void emu_init(void) #endif #endif - while (!SD.begin(SD_CS)) +#ifdef FILEBROWSER + if (!SD.begin(SD_CS)) { - Serial.println("SD begin failed, retrying..."); - delay(1000); + Serial.println("No SD card detected"); } strcpy(selection,ROMSDIR); - FileHandlersInit(); - nbFiles = readNbFiles(); - - Serial.print("SD initialized, files found: "); Serial.println(nbFiles); +#endif emu_InitJoysticks(); #ifdef SWAP_JOYSTICK - joySwapped = true; + joySwapped = true; #else - joySwapped = false; + joySwapped = false; #endif -#ifdef TEECOMPUTER -#ifndef HAS_T4_VGA - tft.flipscreen(false); -#endif -#endif int keypressed = emu_ReadKeys(); +#ifdef HAS_T4_VGA + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } +#else + int gfx_mode = CFG_VGA; // default +#ifdef FILEBROWSER + gfx_mode = emu_readGfxConfig(); +#endif + // Force VGA if UP pressed + if (keypressed & MASK_JOY2_UP) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("VGA"); +#endif + gfx_mode = CFG_VGA; + } + else { + if (keypressed & MASK_JOY2_LEFT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ST"); +#endif + gfx_mode = CFG_ST; + } + else if (keypressed & MASK_JOY2_RIGHT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ILI"); +#endif + gfx_mode = CFG_ILI; + } + } + if (gfx_mode == CFG_VGA) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + else + { + tft.begin(gfx_mode == CFG_ILI?MODE_TFTILI_320x240:MODE_TFTST_320x240); + } +#endif + if (keypressed & MASK_JOY2_DOWN) { tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) ); tft.drawTextNoDma(64,48, (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); +#ifdef FILEBROWSER emu_eraseConfig(); delay(1000); +#endif } else { +#ifdef FILEBROWSER if (emu_readConfig()) { autorun = true; } +#endif } +#ifdef FILEBROWSER toggleMenu(true); +#endif } -void emu_start(void) +void emu_start(int vblms, void * callback, int forcetimervsync) { + vgatimervsync = forcetimervsync?true:false; + tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); + tft.startRefresh(); + if (callback != nullptr) { + vblCallback = callback; + } + + myTimer.begin(vblCount, vblms); +#ifdef HAS_SND + emu_sndInit(); +#endif usbnavpad = 0; } diff --git a/MCUME_teensy41/teensysnes/emuapi.h b/MCUME_teensy41/teensysnes/emuapi.h index 8ee9648..5dd6130 100644 --- a/MCUME_teensy41/teensysnes/emuapi.h +++ b/MCUME_teensy41/teensysnes/emuapi.h @@ -2,127 +2,14 @@ #define EMUAPI_H #include "platform_config.h" - -#define CUSTOM_SND 1 -//#define TIMER_REND 1 -#define EXTPAD 1 - -#define EXTRA_HEAP 0x14000 - -// Title: < > -#define TITLE " SNES Emulator " -#define ROMSDIR "snes" - -#define emu_Init(ROM) { snes_Init(); snes_Start(ROM);} -#define emu_Step(x) { snes_Step(); } -#define emu_Input(x) { snes_Input(x); } - -#define MAX_FILENAME_PATH 64 -#define NB_FILE_HANDLER 4 -#define PALETTE_SIZE 256 -#define VID_FRAME_SKIP 0x0 -#define TFT_VBUFFER_YCROP 0 -#define SINGLELINE_RENDERING 1 - -#define R32(rgb) ((rgb>>16)&0xff) -#define G32(rgb) ((rgb>>8)&0xff) -#define B32(rgb) (rgb & 0xff) +#include "emucfg.h" #define ACTION_NONE 0 -#define ACTION_MAXKBDVAL 16 -#define ACTION_EXITKBD 128 -#define ACTION_RUN1 129 -#define ACTION_RUN2 130 -#define ACTION_RUN3 131 - - -#ifdef KEYMAP_PRESENT - -#define keylables_map0_0 (char *)"QWERTYUIOP\x1a" -#define keylables_map0_1 (char *)" ASDFGHJKL\x19" -#define keylables_map0_2 (char *)" ZXCVBNM,.;/" -#define keylables_map0_3 (char *)" +\x10-" -const unsigned short key_map0[] = { - 'q','w','E','R','T','Y','U','I','O','P',157, //default C64 uppercase always - 0,'A','S','D','F','G','H','J','K','L',10, - 0,'Z','X','C','V','B','N','M',',','.',';','/', - 0,0,0,0, - 0,'+',' ','-' - }; - -#define keylables_map1_0 (char *)"1234567890 " -#define keylables_map1_1 (char *)" " -#define keylables_map1_2 (char *)" " -#define keylables_map1_3 (char *)" " - -const unsigned short key_map1[] = { - '1','2','3','4','5','6','7','8','9','0',0, // digit keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map2_0 (char *)"!\"#$%^&*()@" -#define keylables_map2_1 (char *)" " -#define keylables_map2_2 (char *)" <>:?" -#define keylables_map2_3 (char *)" =\x10_" -const unsigned short key_map2[] = { - '!','"','#','$','%','^','&','*','(',')','@', // shiftothers - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,'<','>',':','?', - 153,151,150,152, //U L R D - 0,'=',' ','_' - }; - -#define keylables_map3_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " -#define keylables_map3_1 (char *)" " -#define keylables_map3_2 (char *)" " -#define keylables_map3_3 (char *)" " - -const unsigned short key_map3[] = { - 129,130,131,132,133,134,135,136,0,0,0, // function keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0, - 0,0,' ',0 - }; - -#define keylables_map4_0 (char *)"QWERTYUIOP@" -#define keylables_map4_1 (char *)" ASDFGHJKL\x19" -#define keylables_map4_2 (char *)" ZXCVBNM<>:?" -#define keylables_map4_3 (char *)" =\x10_" -const unsigned short key_map4[] = { - 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase - 0,'A','S','D','F','G','H','J','K','L',10, - 0,'Z','X','C','V','B','N','M','<','>',':','?', - 0,0,0,0, - 0,'=',' ','_' - }; - -#define keylables_map5_0 (char *)" " -#define keylables_map5_1 (char *)" " -#define keylables_map5_2 (char *)" " -#define keylables_map5_3 (char *)" " - -const unsigned short key_map5[] = { - 0,0,0,0,0,0,0,0,0,0,0, // extra keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 153,151,150,152, //U L R D - 0,0,' ',0 - }; - -const unsigned short matkeys[] = { - 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 - 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 - 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 - 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN - 0x510,0x010,0x110,0x310, // row 4 - }; - -#endif +#define ACTION_RUN1 1 +#define ACTION_RUN2 2 +#define FORCE_VGATIMERVSYNC 1 +#define SUPPORT_HIRES 1 #define MASK_JOY2_RIGHT 0x0001 #define MASK_JOY2_LEFT 0x0002 @@ -139,13 +26,13 @@ const unsigned short matkeys[] = { #define MASK_JOY1_BTN 0x1000 #define MASK_KEY_USER4 0x2000 +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) #ifdef __cplusplus extern "C" { +extern void emu_init(int hires=0); +extern void emu_start(int vblms, void * callback, int forcetimervsync=0); #endif - -extern void emu_init(void); -extern void emu_start(void); extern void emu_printf(const char * text); extern void emu_printi(int val); extern void emu_printh(int val); @@ -157,6 +44,7 @@ extern void emu_SFree(void * pt); extern int emu_FileOpen(const char * filepath, const char * mode); extern int emu_FileRead(void * buf, int size, int handler); +extern int emu_FileWrite(void * buf, int size, int handler); extern int emu_FileGetc(int handler); extern int emu_FileSeek(int handler, int seek, int origin); extern int emu_FileTell(int handler); @@ -167,26 +55,23 @@ extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size); extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek); extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index); -extern void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride); -extern void emu_DrawLine(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line); extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line); +extern void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride); extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line); -extern void emu_CopyLine(int width, int height, int ysrc, int ydst); extern void emu_DrawVsync(void); extern int emu_FrameSkip(void); -extern void * emu_LineBuffer(int line); -extern int emu_LineStride(void); -extern int emu_LineWidth(void); -extern void emu_tweakVideo(int shiftdelta, int numdelta, int denomdelta); +extern int emu_IsVga(void); +extern int emu_IsVgaHires(void); -extern bool menuActive(void); +extern int menuActive(void); extern char * menuSelection(void); extern char * menuSecondSelection(void); -extern void toggleMenu(bool on); +extern void toggleMenu(int on); extern int handleMenu(unsigned short bClick); extern int handleOSKB(void); -extern void toggleOSKB(bool forceon); +extern void toggleOSKB(int forceon); extern void emu_InitJoysticks(void); extern int emu_SwapJoysticks(int statusOnly); diff --git a/MCUME_teensy41/teensysnes/emucfg.h b/MCUME_teensy41/teensysnes/emucfg.h new file mode 100644 index 0000000..60a1c75 --- /dev/null +++ b/MCUME_teensy41/teensysnes/emucfg.h @@ -0,0 +1,115 @@ +#ifndef EMUCFG_H +#define EMUCFG_H + +#include "wrapemu.h" + +// Title: < > +#define TITLE " SNES Emulator " +#define ROMSDIR "snes" + +#define emu_Init(ROM) { snes_Init(); snes_Start(ROM);} +#define emu_Step(x) { snes_Step(); } +#define emu_Input(x) { snes_Input(x); } + +#define MAX_FILENAME_PATH 64 +#define NB_FILE_HANDLER 4 + +#define PALETTE_SIZE 256 +#define VID_FRAME_SKIP 0x0 +#define TFT_VBUFFER_YCROP 0 +#define SINGLELINE_RENDERING 1 +#define CUSTOM_SND 1 +//#define TIMER_REND 1 +#define EXTPAD 1 +#define EXTRA_HEAP 0x1A000 +#define FILEBROWSER 1 + + +#ifdef KEYMAP_PRESENT + +#define keylables_map0_0 (char *)"QWERTYUIOP\x1a" +#define keylables_map0_1 (char *)" ASDFGHJKL\x19" +#define keylables_map0_2 (char *)" ZXCVBNM,.;/" +#define keylables_map0_3 (char *)" +\x10-" +const unsigned short key_map0[] = { + 'q','w','E','R','T','Y','U','I','O','P',157, //default C64 uppercase always + 0,'A','S','D','F','G','H','J','K','L',10, + 0,'Z','X','C','V','B','N','M',',','.',';','/', + 0,0,0,0, + 0,'+',' ','-' + }; + +#define keylables_map1_0 (char *)"1234567890 " +#define keylables_map1_1 (char *)" " +#define keylables_map1_2 (char *)" " +#define keylables_map1_3 (char *)" " + +const unsigned short key_map1[] = { + '1','2','3','4','5','6','7','8','9','0',0, // digit keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map2_0 (char *)"!\"#$%^&*()@" +#define keylables_map2_1 (char *)" " +#define keylables_map2_2 (char *)" <>:?" +#define keylables_map2_3 (char *)" =\x10_" +const unsigned short key_map2[] = { + '!','"','#','$','%','^','&','*','(',')','@', // shiftothers + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 153,151,150,152, //U L R D + 0,'=',' ','_' + }; + +#define keylables_map3_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " +#define keylables_map3_1 (char *)" " +#define keylables_map3_2 (char *)" " +#define keylables_map3_3 (char *)" " + +const unsigned short key_map3[] = { + 129,130,131,132,133,134,135,136,0,0,0, // function keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0, + 0,0,' ',0 + }; + +#define keylables_map4_0 (char *)"QWERTYUIOP@" +#define keylables_map4_1 (char *)" ASDFGHJKL\x19" +#define keylables_map4_2 (char *)" ZXCVBNM<>:?" +#define keylables_map4_3 (char *)" =\x10_" +const unsigned short key_map4[] = { + 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase + 0,'A','S','D','F','G','H','J','K','L',10, + 0,'Z','X','C','V','B','N','M','<','>',':','?', + 0,0,0,0, + 0,'=',' ','_' + }; + +#define keylables_map5_0 (char *)" " +#define keylables_map5_1 (char *)" " +#define keylables_map5_2 (char *)" " +#define keylables_map5_3 (char *)" " + +const unsigned short key_map5[] = { + 0,0,0,0,0,0,0,0,0,0,0, // extra keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 153,151,150,152, //U L R D + 0,0,' ',0 + }; + +const unsigned short matkeys[] = { + 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 + 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 + 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 + 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN + 0x510,0x010,0x110,0x310, // row 4 + }; + +#endif + +#endif diff --git a/MCUME_teensy41/teensysnes/gfx.cpp b/MCUME_teensy41/teensysnes/gfx.cpp index 670aa9e..9d3a786 100644 --- a/MCUME_teensy41/teensysnes/gfx.cpp +++ b/MCUME_teensy41/teensysnes/gfx.cpp @@ -1538,13 +1538,13 @@ bool8 S9xGraphicsInit (void) S9xInitTileRenderer(); - GFX.Screen = (SNESPixel*)emu_LineBuffer(0)+(emu_LineWidth()-256)/2; - //GFX.SubScreen = GFX.Screen; + GFX.Screen = (SNESPixel *) emu_Malloc(GFX.ScreenSize * sizeof(SNESPixel)); GFX.SubScreen = (SNESPixel *) emu_SMalloc(GFX.ScreenSize * sizeof(SNESPixel)); - - GFX.ZBuffer = (uint8 *) emu_Malloc(GFX.ScreenSize); + memset((unsigned char*)GFX.Screen, 0, GFX.ScreenSize * sizeof(SNESPixel)); + memset((unsigned char*)GFX.SubScreen, 0, GFX.ScreenSize * sizeof(SNESPixel)); + GFX.ZBuffer = (uint8 *) emu_Malloc(GFX.ScreenSize); GFX.SubZBuffer = (uint8 *) emu_Malloc(GFX.ScreenSize); - GFX.ZERO = (SNESPixel *) GFX.SubScreen; // This will cause garbage but for now it's okay + //GFX.ZERO = (SNESPixel *) GFX.SubScreen; // This will cause garbage but for now it's okay IPPU.TileCacheData = (uint8 *) emu_SMalloc(4096 * 64); if (!GFX.SubScreen || !GFX.ZBuffer || !GFX.SubZBuffer || !IPPU.TileCacheData) @@ -1556,7 +1556,7 @@ bool8 S9xGraphicsInit (void) #if 0 // TO DO: pre-compute GFX.ZERO // Lookup table for 1/2 color subtraction - memset(GFX.ZERO, 0, 0x10000 * sizeof(uint16)); + //memset(GFX.ZERO, 0, 0x10000 * sizeof(uint16)); for (uint8 r = 0; r <= MAX_RED; r++) { uint8 r2 = (r & 0x10) ? (r & ~0x10) : (0); diff --git a/MCUME_teensy41/teensysnes/memory.cpp b/MCUME_teensy41/teensysnes/memory.cpp index 4a9840d..60eb2c3 100644 --- a/MCUME_teensy41/teensysnes/memory.cpp +++ b/MCUME_teensy41/teensysnes/memory.cpp @@ -624,9 +624,9 @@ bool8 S9xMemoryInit (void) memset(&Memory, 0, sizeof(Memory)); Memory.RAM = (uint8 *) emu_Malloc(0x20000); // calloc(1, 0x20000); // 128k - Memory.VRAM = (uint8 *) emu_Malloc(0x10000); //calloc(1, 0x10000); // 64k + Memory.VRAM = (uint8 *) emu_SMalloc(0x10000); //calloc(1, 0x10000); // 64k Malloc? Memory.SRAM = (uint8 *) emu_Malloc(0x8000); //calloc(1, 0x8000); // 32k - Memory.ROM_MAX_SIZE = 0x500000; + Memory.ROM_MAX_SIZE = 0x600000; //Memory.ROM = (uint8 *) calloc(1, Memory.ROM_MAX_SIZE); // Note: we don't care if ROM alloc fails. It's just to grab a large heap block // before it gets fragmented. The actual useful alloc is done in S9xLoadROM() diff --git a/MCUME_teensy41/teensysnes/platform_config.h b/MCUME_teensy41/teensysnes/platform_config.h index 17ab542..02c3ee5 100644 --- a/MCUME_teensy41/teensysnes/platform_config.h +++ b/MCUME_teensy41/teensysnes/platform_config.h @@ -3,14 +3,16 @@ #define TEECOMPUTER 1 +#define TFT_WIDTH 256 +#define TFT_HEIGHT 224 + #ifdef TEECOMPUTER -//#define ILI9341 1 -#define ST7789 1 #define TFTSPI1 1 //#define HAS_T4_VGA 1 #define HAS_SND 1 -#define HAS_USB 1 +//#define HAS_USB 1 //#define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 //#define HAS_USBMIDI 1 //#define HAS_USBJOY 1 // not working yet //#define INVX 1 @@ -22,11 +24,18 @@ //#define INVX 1 #define INVY 1 #define HAS_SND 1 +//#define HAS_USB 1 //#define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 +//#define HAS_USBJOY 1 // not working yet +//#define INVX 1 +#define PT8211 1 #endif +//#define FLIP_SCREEN 1 //#define ILI9341 1 //#define ST7789 1 //#define SWAP_JOYSTICK 1 diff --git a/MCUME_teensy41/teensysnes/port.h b/MCUME_teensy41/teensysnes/port.h index 67af21f..7f40557 100644 --- a/MCUME_teensy41/teensysnes/port.h +++ b/MCUME_teensy41/teensysnes/port.h @@ -51,12 +51,9 @@ typedef uint64_t uint64; #define FALSE 0 #endif -#ifndef HAS_T4_VGA -#define GFX16 1 -typedef uint16 SNESPixel; -#else +//#define GFX16 1 +//typedef uint16 SNESPixel; typedef uint8 SNESPixel; -#endif #if defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__x86_64__) || defined(__alpha__) || defined(__MIPSEL__) || defined(_M_IX86) || defined(_M_X64) || defined(_XBOX1) || defined(__arm__) || defined(ANDROID) || defined(__aarch64__) || (defined(__BYTE_ORDER__) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN__) || defined(IS_LITTLE_ENDIAN) diff --git a/MCUME_teensy41/teensysnes/snes9x.cpp b/MCUME_teensy41/teensysnes/snes9x.cpp index e48b680..23c5134 100644 --- a/MCUME_teensy41/teensysnes/snes9x.cpp +++ b/MCUME_teensy41/teensysnes/snes9x.cpp @@ -12,11 +12,9 @@ #include "gfx.h" //#include "snapshot.h" - struct SSettings Settings; char String[513]; - void S9xInitSettings(void) { memset(&Settings, 0, sizeof(Settings)); @@ -61,6 +59,19 @@ void s9x_init(void) { Settings.ReverseStereo = false; Settings.PAL = true; //false; + if ( !emu_IsVga() ) { + int index = 0; + for (int r=0; r<8; r++) { + for (int g=0; g<8; g++) { + for (int b=0; b<4; b++) { + if (index < PALETTE_SIZE) { + emu_SetPaletteEntry(r<<5, g<<5, b<<6, index++); + } + } + } + } + } + if (!S9xMemoryInit()) emu_printf("Memory init failed!"); @@ -99,6 +110,9 @@ void s9x_step(void) { } //IPPU.RenderThisFrame = (((++frames_counter) & Settings.SkipFrames) == Settings.SkipFrames); //GFX.Screen = (uint16*)currentUpdate->buffer; + for (int j=0; j +#include + +#include "font8x8.h" + +// TFT constants and variables +#define TFT_LINEARINT 1 +#define LINEARINT_HACK 1 +#define DMA_LINES_PER_BLOCK 64 +#define DMA_NUM_SETTINGS 4 + +#define TFT_SWRESET 0x01 +#define TFT_SLPOUT 0x11 +#define TFT_INVON 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_MADCTL 0x36 +#define TFT_PIXFMT 0x3A +#define TFT_MADCTL_MY 0x80 +#define TFT_MADCTL_MX 0x40 +#define TFT_MADCTL_MV 0x20 +#define TFT_MADCTL_ML 0x10 +#define TFT_MADCTL_RGB 0x00 +#define TFT_MADCTL_BGR 0x08 +#define TFT_MADCTL_MH 0x04 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) +//#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) +//#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) +//#define R16(rgb) ((rgb>>8)&0xf8) +//#define G16(rgb) ((rgb>>3)&0xfc) +//#define B16(rgb) ((rgb<<3)&0xf8) + +// LPSPI4 = SPI0 in Teensy 4.0 +// LPSPI3 = SPI1 in Teensy 4.0 +// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) + +#ifdef TFTSPI1 +#define SPI SPI1 +#define LPSPIP_TDR LPSPI3_TDR +#define LPSPIP_CR LPSPI3_CR +#define LPSPIP_CFGR1 LPSPI3_CFGR1 +#define LPSPIP_TCR LPSPI3_TCR +#define LPSPIP_DER LPSPI3_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX +#else +#define LPSPIP_TDR LPSPI4_TDR +#define LPSPIP_CR LPSPI4_CR +#define LPSPIP_CFGR1 LPSPI4_CFGR1 +#define LPSPIP_TCR LPSPI4_TCR +#define LPSPIP_DER LPSPI4_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX +#endif + +#define SPICLOCK 60000000 +#define SPI_MODE SPI_MODE0 + +// VGA constants and macros +typedef uint8_t vga_pixel; +#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) + +static DMASetting dmasettings[DMA_NUM_SETTINGS]; +static DMAChannel dmatx; +static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K +static volatile uint8_t rstop = 0; +static volatile bool cancelled = false; +static volatile uint8_t curTransfer = 0; +static uint8_t nbTransfer = 0; +static uint16_t * tft_buffer; +static int tft_width; +static int tft_height; +static int tft_stride; + +#define DELAY_MASK 0x80 +PROGMEM static const uint8_t init_commands[] = { + 1+DELAY_MASK, TFT_SWRESET, 150, + 1+DELAY_MASK, TFT_SLPOUT, 255, + 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, + 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, + 1, TFT_INVON, + 1, TFT_DISPON, + 0 +}; + +// VGA constants and variables +// Objective: +// generates VGA signal fully in hardware with as little as possible CPU help + +// Principle: +// QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) +// 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate +// RGB out, combined to create 8bits(/12bits) output. + +// Note: +// - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels +// - experimental resolution: 352x240,352x480 +// - experimental resolution: 512x240,512x480 (not stable) +// - video memory is allocated using malloc in T4 heap +// - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing +// but tried to be compensated by pixel shifting +// - Default is 8bits RRRGGGBB (332) +// But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! +// - Only ok at 600MHz else some disturbances visible + + + +#define TOP_BORDER 40 +#define PIN_HBLANK 15 + +#define PIN_R_B2 33 +#define PIN_R_B1 4 +#define PIN_R_B0 3 +#define PIN_G_B2 2 +#define PIN_G_B1 13 +#define PIN_G_B0 11 +#define PIN_B_B1 12 +#define PIN_B_B0 10 + + +#define DMA_HACK 0x80 + +#define R16(rgb) ((rgb>>8)&0xf8) +#define G16(rgb) ((rgb>>3)&0xfc) +#define B16(rgb) ((rgb<<3)&0xf8) + +// VGA 640x480@60Hz +// Screen refresh rate 60 Hz +// Vertical refresh 31.46875 kHz +// Pixel freq. 25.175 MHz +// +// Visible area 640 25.422045680238 us +// Front porch 16 0.63555114200596 us +// Sync pulse 96 3.8133068520357 us +// Back porch 48 1.9066534260179 us +// Whole line 800 31.777557100298 us + +#define frame_freq 60.0 // Hz +#define line_freq 31.46875 // KHz +#define pix_freq (line_freq*800) // KHz (25.175 MHz) + +// pix_period = 39.7ns +// H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) +#define frontporch_pix 20 //16 +#define backporch_pix 44 //48 + +// Flexio Clock +// PLL3 SW CLOCK (3) => 480 MHz +// PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) +#define FLEXIO_CLK_SEL_PLL3 3 +#define FLEXIO_CLK_SEL_PLL5 2 + +/* Set video PLL */ +// There are /1, /2, /4, /8, /16 post dividers for the Video PLL. +// The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, +// and CCM_ANALOG_MISC2 register sets according to the following equation. +// PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + +// nfact: +// This field controls the PLL loop divider. +// Valid range for DIV_SELECT divider value: 27~54. + +#define POST_DIV_SELECT 2 + +// Full buffer including back/front porch +static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; +static uint32_t dstbuffer __attribute__((aligned(32))); + +// Visible vuffer +static vga_pixel * vga_buffer; +static int vga_width; +static int vga_height; +static int vga_stride; + +static int maxpixperline; +static int left_border; +static int right_border; +static int line_double; +static int pix_shift; +static int ref_div_select; +static int ref_freq_num; +static int ref_freq_denom; +static int ref_pix_shift; +static int combine_shiftreg; + +#ifdef DEBUG +static uint32_t ISRTicks_prev = 0; +volatile uint32_t ISRTicks = 0; +#endif + +uint8_t T4_DSP::_rst; +uint8_t T4_DSP::_cs; +uint8_t T4_DSP::_dc; +uint8_t T4_DSP::_mosi; +uint8_t T4_DSP::_sclk; +uint8_t T4_DSP::_vsync_pin = -1; +DMAChannel T4_DSP::flexio1DMA; +DMAChannel T4_DSP::flexio2DMA; + +static volatile uint32_t VSYNC = 0; +static volatile uint32_t currentLine=0; +#define NOP asm volatile("nop\n\t"); +static gfx_mode_t gfxmode = MODE_UNDEFINED; + + +FASTRUN void T4_DSP::TFT_isr(void) { + dmatx.clearInterrupt(); + curTransfer++; + if (curTransfer >= nbTransfer) { + curTransfer = 0; + if (cancelled) { + dmatx.disable(); + rstop = 1; + } + } + arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); +} + +FASTRUN void T4_DSP::QT3_isr(void) { + TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); + TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); + + cli(); + + // V-PULSE + if (currentLine > 0) { + digitalWrite(_vsync_pin, 1); + VSYNC = 0; + } else { + digitalWrite(_vsync_pin, 0); + VSYNC = 1; + } + + currentLine++; + currentLine = currentLine % 525; + + + uint32_t y = (currentLine - TOP_BORDER) >> line_double; + // Visible area + + if (y >= 0 && y < vga_height) { + // Disable DMAs + //DMA_CERQ = flexio2DMA.channel; + //DMA_CERQ = flexio1DMA.channel; + + // Setup source adress + // Aligned 32 bits copy + unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; + flexio2DMA.TCD->SADDR = p; + if (pix_shift & DMA_HACK) + { + // Unaligned copy + uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; + flexio1DMA.TCD->SADDR = p2; + } + else { + p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 + flexio1DMA.TCD->SADDR = p; + } + + // Enable DMAs + //flexio2DMA.enable(); + //flexio1DMA.enable(); + DMA_SERQ = flexio2DMA.channel; + DMA_SERQ = flexio1DMA.channel; + arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); + } + sei(); + +#ifdef DEBUG + ISRTicks++; +#endif + asm volatile("dsb"); +} + +static void setDmaStruct() { + uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; + uint16_t * fb = (uint16_t*)malloc(remaining); + tft_buffer = fb; + tft_width = TFT_WIDTH; + tft_height = TFT_HEIGHT; + tft_stride = TFT_WIDTH; + uint16_t col=RGBVAL16(0x00,0x00,0x00); + int i=0; + while (remaining > 0) { + int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); + blocks[i] = fb; + for (int j=0;jATTR_DST = 1; + dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); + dmasettings[i].interruptAtCompletion(); + fb += len/2; + remaining -= len; + i++; + } + dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); + nbTransfer = i; +} + +static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 +{ +//if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; + CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE + | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 + | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); + CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; + CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock + const int div_post_pll = 1; // other values: 2,4 + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass +} + +T4_DSP::T4_DSP() +{ + _cs = TFT_CS; + _dc = TFT_DC; + _rst = TFT_RST; + _mosi = TFT_MOSI; + _sclk = TFT_SCLK; + pinMode(_dc, OUTPUT); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, 1); + digitalWrite(_dc, 1); + _vsync_pin = 8; +} + + +void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { + int dx=0; + int dy=0; + digitalWrite(_dc, 0); + SPI.transfer(TFT_CASET); + digitalWrite(_dc, 1); + SPI.transfer16(x1+dx); + digitalWrite(_dc, 1); + SPI.transfer16(x2+dx); + digitalWrite(_dc, 0); + SPI.transfer(TFT_PASET); + digitalWrite(_dc, 1); + SPI.transfer16(y1+dy); + digitalWrite(_dc, 1); + SPI.transfer16(y2+dy); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + return; +} + +void T4_DSP::tft_setup(bool isST) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + // RESET if reset pin defined + if (_rst != 0xff) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + const uint8_t *addr = init_commands; + uint8_t count; + digitalWrite(_cs, 0); + while (count = *addr++) { + uint8_t command = *addr++; + if ( (command == TFT_INVON) && (!isST) ) { + // Skip TFT_INVON for ILI + } + else { + digitalWrite(_dc, 0); // command + SPI.transfer(command); + uint16_t ms = count & DELAY_MASK; + count &= ~DELAY_MASK; + while (--count > 0) { // data + uint8_t data = *addr++; + if ( (command == TFT_MADCTL) && (isST) ) { + data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; + } + digitalWrite(_dc, 1); + SPI.transfer(data); + } + if (ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + digitalWrite(_cs, 1); + SPI.endTransaction(); + delay(2); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + } + } + } + digitalWrite(_cs, 1); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + SPI.endTransaction(); + /* + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_dc, 0); + digitalWrite(_cs, 0); + SPI.transfer(TFT_MADCTL); + digitalWrite(_dc, 1); + SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); + // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); + digitalWrite(_cs, 1); + SPI.endTransaction(); + */ + cancelled = false; +} + +// display VGA image +gfx_error_t T4_DSP::begin(gfx_mode_t mode) +{ + uint32_t flexio_clock_div; + combine_shiftreg = 0; +// int div_select = 49; +// int num = 135; +// int denom = 100; + int div_select = 20; + int num = 9800; + int denom = 10000; + int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; + int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; + set_videoClock(div_select,num,denom,true); + +#ifdef DEBUG + Serial.println(mode); + Serial.println("mode"); +#endif + + switch(mode) + { + case MODE_TFTILI_320x240: +#ifdef DEBUG + Serial.println("TFTILI_320x240"); +#endif + tft_setup(false); + gfxmode = mode; + break; + case MODE_TFTST_320x240: +#ifdef DEBUG + Serial.println("TFTST_320x240"); +#endif + tft_setup(true); + gfxmode = mode; + break; + + case MODE_VGA_320x240: +#ifdef DEBUG + Serial.println("VGA_320x240"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_320x480: +#ifdef DEBUG + Serial.println("VGA_320x480"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_640x240: +#ifdef DEBUG + Serial.println("VGA_640x240"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/pix_freq; + line_double = 1; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_640x480: +#ifdef DEBUG + Serial.println("VGA_640x480"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = (flexio_freq/pix_freq); + line_double = 0; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_512x240: +#ifdef DEBUG + Serial.println("VGA_512x240"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 1; + pix_shift = 0; + break; + + case MODE_VGA_512x480: +#ifdef DEBUG + Serial.println("VGA_512x480"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 0; + pix_shift = 0; + break; + + case MODE_VGA_352x240: +#ifdef DEBUG + Serial.println("VGA_352x240"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_352x480: +#ifdef DEBUG + Serial.println("VGA_352x480"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + } + + if (mode >= MODE_VGA_320x240) + { + if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { + fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); + digitalWrite(_cs, 0); + digitalWrite(_dc, 0); + SPI.transfer(TFT_DISPOFF); + digitalWrite(_cs, 1); + delay(20); + digitalWrite(_cs, 0); + digitalWrite(_cs, 1); + } + gfxmode = mode; + + maxpixperline = vga_stride; + // Save param for tweek adjustment + ref_div_select = div_select; + ref_freq_num = num; + ref_freq_denom = denom; + ref_pix_shift = pix_shift; + +#ifdef DEBUG + Serial.println("frequency"); + Serial.println(flexio_freq); + Serial.println("div"); + Serial.println(flexio_freq/pix_freq); +#endif + + pinMode(_vsync_pin, OUTPUT); + pinMode(PIN_HBLANK, OUTPUT); + + /* Basic pin setup FlexIO1 */ + pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 + pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 + pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 + pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 + /* Basic pin setup FlexIO2 */ + pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 + pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 + pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 + pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 + + /* High speed and drive strength configuration */ + *(portControlRegister(PIN_G_B2)) = 0xFF; + *(portControlRegister(PIN_R_B0)) = 0xFF; + *(portControlRegister(PIN_R_B1)) = 0xFF; + *(portControlRegister(PIN_R_B2)) = 0xFF; + *(portControlRegister(PIN_B_B0)) = 0xFF; + *(portControlRegister(PIN_B_B1)) = 0xFF; + *(portControlRegister(PIN_G_B0)) = 0xFF; + *(portControlRegister(PIN_G_B1)) = 0xFF; + + /* Set clock for FlexIO1 and FlexIO2 */ + CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) + | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); + CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) + | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); + + + /* Set up pin mux FlexIO1 */ + *(portConfigRegister(PIN_G_B2)) = 0x14; + *(portConfigRegister(PIN_R_B0)) = 0x14; + *(portConfigRegister(PIN_R_B1)) = 0x14; + *(portConfigRegister(PIN_R_B2)) = 0x14; + /* Set up pin mux FlexIO2 */ + *(portConfigRegister(PIN_B_B0)) = 0x14; + *(portConfigRegister(PIN_B_B1)) = 0x14; + *(portConfigRegister(PIN_G_B0)) = 0x14; + *(portConfigRegister(PIN_G_B1)) = 0x14; + + /* Enable the clock */ + CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + /* Enable the FlexIO with fast access */ + FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + + uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; + uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; + + /* Shifter 0 registers for FlexIO2 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 + inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter + stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled + startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable + timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 + timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock + pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output + pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity + shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode + /* Shifter 0 registers for FlexIO1 */ + FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + /* Shifter 0 registers for FlexIO1 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 + FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + if (combine_shiftreg) { + pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled + FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + } + /* Timer 0 registers for FlexIO2 */ + timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset + timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output + timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset + timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare + timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert + stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled + startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled + if (combine_shiftreg) { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag + } + else { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag + } + triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low + triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected + pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled + //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 + //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high + timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode + // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) + + int shifts_per_transfer; + if (combine_shiftreg) { + shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 + } + else { + shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 + } + FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); + /* Timer 0 registers for FlexIO1 */ + FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); +#ifdef DEBUG + Serial.println("FlexIO setup complete"); +#endif + + /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ + if (combine_shiftreg) { + FLEXIO2_SHIFTSDEN |= (1<<1); + FLEXIO1_SHIFTSDEN |= (1<<1); + } + else { + FLEXIO2_SHIFTSDEN |= (1<<0); + FLEXIO1_SHIFTSDEN |= (1<<0); + } + /* Disable DMA channel so it doesn't start transferring yet */ + flexio1DMA.disable(); + flexio2DMA.disable(); + /* Set up DMA channel to use Shifter 0 trigger */ + flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); + flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); + + + if (combine_shiftreg) { + flexio2DMA.TCD->NBYTES = 8; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 8; + flexio2DMA.TCD->CITER = maxpixperline / 8; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + flexio1DMA.TCD->NBYTES = 8; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 8; + flexio1DMA.TCD->CITER = maxpixperline / 8; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Setup DMA2 Flexio2 copy + flexio2DMA.TCD->NBYTES = 4; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 4; + flexio2DMA.TCD->CITER = maxpixperline / 4; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + // Setup DMA1 Flexio1 copy + // Use pixel shift to avoid color smearing? + if (pix_shift & DMA_HACK) + { + if (pix_shift & 0x3 == 0) { + // Aligned 32 bits copy (32bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Unaligned (source) 32 bits copy (8bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 1; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion + } + } + else + { + // Aligned 32 bits copy + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + } + +#ifdef DEBUG + Serial.println("DMA setup complete"); +#endif + + // enable clocks for QTIMER3: generates the 15KHz for hsync + // Pulse: + // low : 3.8133 us => 569x6.7ns + // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) + // (OLD TEST) + // (4us low, 28us high => 32us) + // (597x6.7ns for 4us) + // (4179x6.7ns for 28us) + CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 + //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 + + #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz + #define MARGIN_D 1000 + + TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer + // Invert output pin as we want the interupt on rising edge + TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) + TMR3_CNTR3 = 0; + TMR3_LOAD3 = 0; + + /* Inverted timings */ + unsigned long long cpu_freq = F_CPU; + unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; + int rate2 = rate; + + int substract = 1; + if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { + substract=5; + rate2=1652; + } + + #ifdef DEBUG + Serial.print("MARGIN_N is: "); + Serial.println(rate2, DEC); + Serial.print("SUBSTRACT is: "); + Serial.println(substract, DEC); +#endif + TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; + TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; + /* + TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; + */ + TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on + TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), + // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) + //configure Teensy pin Compare output + IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 + attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function + NVIC_ENABLE_IRQ(IRQ_QTIMER3); +#ifdef DEBUG + Serial.println("QTIMER3 setup complete"); + Serial.print("V-PIN is "); + Serial.println(_vsync_pin); +#endif + + /* initialize gfx buffer */ + if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift + if (gfxbuffer == NULL) return(GFX_ERROR); +#ifdef DEBUG + Serial.println("Memory allocated"); +#endif + + memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); + vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; +#ifdef DEBUG + Serial.println(vga_stride); + Serial.println(vga_height); + Serial.println("Screen cleared"); +#endif + } + + return(GFX_OK); +} + +gfx_mode_t T4_DSP::getMode(void) +{ + return gfxmode; +} + +void T4_DSP::startRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + curTransfer = 0; + rstop = 0; + //dmatx.begin(true); + dmatx.attachInterrupt(TFT_isr); + setDmaStruct(); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + + digitalWrite(_cs, HIGH); + SPI.begin(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + + LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: + LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX + LPSPIP_TCR = 15; // Framesize 16 Bits + //LPSPIP_FCR = 0; // Fifo Watermark + LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable + LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: + dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); + + dmatx = dmasettings[0]; + digitalWrite(_cs, 0); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + dmatx.enable(); + } +} + + +void T4_DSP::stopRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + rstop = 1; + unsigned long m = millis(); + cancelled = true; + while (!rstop) { + if ((millis() - m) > 100) break; + delay(10); + asm volatile("wfi"); + }; + rstop = 0; + delay(50); + cancelled = false; + dmatx.detachInterrupt(); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + SPI.end(); +#ifdef ST7789 +// begin(gfxmode); +#endif + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + } +} + +int T4_DSP::get_frame_buffer_size(int *width, int *height) { + if (gfxmode < MODE_VGA_320x240) { + if (width != nullptr) *width = tft_width; + if (height != nullptr) *height = tft_height; + return tft_stride; + } + else { + if (width != nullptr) *width = vga_width; + if (height != nullptr) *height = vga_height; + return vga_stride; + } +} + +void T4_DSP::waitSync() +{ + if (gfxmode >= MODE_VGA_320x240) { + while (VSYNC == 0) {}; + } +} + +void T4_DSP::waitLine(int line) +{ + if (gfxmode >= MODE_VGA_320x240) { + while (currentLine != line) {}; + } +} + +/*********************************************************************************************** + No DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreenNoDma(uint16_t color) { + if (gfxmode < MODE_VGA_320x240) { + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + int i,j; + for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(arx, ary, arx+arw-1, ary+arh-1); + bitmap = bitmap + bmp_offy*w + bmp_offx; + for (int row=0;row> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + bits = *charpt++; + //digitalWrite(_dc, 1); + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + x +=8; + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + else { + drawText(x, y, text, fgcolor, bgcolor, doublesize); + } +} + + +/*********************************************************************************************** + DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreen(uint16_t color) { + int i,j; + if (gfxmode < MODE_VGA_320x240) { + for (j=0; j> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + dst=&tft_buffer[l*tft_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + x +=8; + } + } + else { + vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); + vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); + vga_pixel * dst; + while ((c = *text++)) { + const unsigned char * charpt=&font8x8[c][0]; + int l=y; + for (int i=0;i<8;i++) + { + unsigned char bits; + if (doublesize) { + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + x +=8; + } + } +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { + drawSprite(x,y,bitmap, 0,0,0,0); +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) +{ + int bmp_offx = 0; + int bmp_offy = 0; + uint16_t *bmp_ptr; + int w =*bitmap++; + int h = *bitmap++; + if ( (arw == 0) || (arh == 0) ) { + // no crop window + arx = x; + ary = y; + arw = w; + arh = h; + } + else { + if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + int l=ary; + bitmap = bitmap + bmp_offy*w + bmp_offx; + + if (gfxmode < MODE_VGA_320x240) { + for (int row=0;row tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]; + pos +=step; + } + #endif + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i 2) ) y += (tft_height-height)/2; + uint16_t * dst=&tft_buffer[y*tft_stride]; + if (width > tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]]; + pos +=step; + } +#endif + } + else if ((width*2) == tft_width) { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]]; + *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i tft_width) { + int step = ((width << 8)/tft_width); + int pos = 0; + for (int i=0; i> 8]]; + pos +=step; + } + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = pix; + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i +#include +#endif + +#include "platform_config.h" +#include "iopins.h" + + + +#ifndef TFT_WIDTH +#define TFT_WIDTH 320 +#endif +#define TFT_REALWIDTH 320 + +#ifndef TFT_HEIGHT +#define TFT_HEIGHT 240 +#endif +#define TFT_REALHEIGHT 240 + + +typedef enum gfx_mode_t +{ + MODE_UNDEFINED = 0, + MODE_TFTILI_320x240 = 1, + MODE_TFTST_320x240 = 2, + MODE_VGA_320x240 = 3, + MODE_VGA_320x480 = 4, + MODE_VGA_352x240 = 5, + MODE_VGA_352x480 = 6, + MODE_VGA_512x240 = 7, + MODE_VGA_512x480 = 8, + MODE_VGA_640x240 = 9, + MODE_VGA_640x480 = 10 +} gfx_mode_t; + +typedef enum gfx_error_t +{ + GFX_OK = 0, + GFX_ERROR = -1 +} gfx_error_t; + + +#ifdef __cplusplus + +class T4_DSP +{ + public: + T4_DSP(); + + gfx_error_t begin(gfx_mode_t mode); + gfx_mode_t getMode(void); + void startRefresh(void); + void stopRefresh(); + + int get_frame_buffer_size(int *width, int *height); + void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); + + // wait next Vsync + void waitSync(); + void waitLine(int line); + + // NoDMA functions + void fillScreenNoDma(uint16_t color); + void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + // DMA functions + void fillScreen(uint16_t color); + void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + void writeLine(int width, int height, int y, uint16_t *buf); + void writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + void writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16); + void writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + + protected: + static uint8_t _rst, _cs, _dc; + static uint8_t _mosi, _sclk; + static uint8_t _vsync_pin; + static DMAChannel flexio1DMA; + static DMAChannel flexio2DMA; + void tft_setup(bool isST); + static void TFT_isr(void); + static void QT3_isr(void); +}; + +#endif +#endif diff --git a/MCUME_teensy41/teensysnes/teensysnes.ino b/MCUME_teensy41/teensysnes/teensysnes.ino index a650655..4acb9f8 100644 --- a/MCUME_teensy41/teensysnes/teensysnes.ino +++ b/MCUME_teensy41/teensysnes/teensysnes.ino @@ -3,148 +3,16 @@ extern "C" { #include "iopins.h" } -#include "snes.h" - -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -TFT_T_DMA tft; -#else -#include "tft_t_dma.h" -TFT_T_DMA tft = TFT_T_DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, TFT_TOUCH_CS, TFT_TOUCH_INT); -#endif - -bool vgaMode = false; - -static unsigned char palette8[PALETTE_SIZE]; -static unsigned short palette16[PALETTE_SIZE]; -static IntervalTimer myTimer; -volatile boolean vbl=true; -static int skip=0; -static elapsedMicros tius; -static int fbstride; -static int fbwidth; -static int fbheight; - -static void vblCount() { - if (vbl) { - vbl = false; - } else { - vbl = true; - } -} - -void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) -{ - if (index>8, - 320 & 0xFF, // YEND = 320 - ST7735_INVON , DELAY, // 7: hack - 10, - ST7735_NORON , DELAY, // 8: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 9: Main screen turn on, no args, w/delay - 255 -#endif -}; - -static void dmaInterrupt() { - dmatx.clearInterrupt(); - curTransfer++; - if (curTransfer >= nbTransfer) { - curTransfer = 0; - if (cancelled) { - dmatx.disable(); - rstop = 1; - } - } - arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2); -} - -static void setDmaStruct() { - uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; - int i=0; - uint16_t col=RGBVAL16(0x00,0x00,0x00); - uint16_t * fb = (uint16_t*)((int)malloc(remaining+64)&0xffffffe0); - while (remaining > 0) { - //uint16_t * fb = blocks[i]; - int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining); -#ifdef TFT_DEBUG - Serial.println((unsigned long)blocks[i]); - Serial.println(remaining); -#endif - switch (i) { - case 0: - //if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb0[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0x00); -#endif - break; - case 1: - //if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb1[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0xff); -#endif - break; - case 2: - //if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb2[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0x00,0xff); -#endif - break; - case 3: - //if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb3[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0xff,0x00,0xff); -#endif - break; - } - blocks[i] = fb; - if (blocks[i] == 0) { - Serial.print("ILI9341 allocaltion failed for block "); - Serial.println(i); - delay(10000); - } - - for (int j=0;jATTR_DST = 1; - dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); - dmasettings[i].interruptAtCompletion(); - fb += len/2; - remaining -= len; - i++; - } - dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); - nbTransfer = i; -#ifdef TFT_DEBUG - Serial.println(nbTransfer); -#endif -} - - -TFT_T_DMA::TFT_T_DMA(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso, uint8_t touch_cs, uint8_t touch_irq) -{ - _cs = cs; - _dc = dc; - _rst = rst; - _mosi = mosi; - _sclk = sclk; - _miso = miso; - pinMode(_dc, OUTPUT); - pinMode(_cs, OUTPUT); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); - if ( (touch_cs != 255) && (touch_irq != 255) ) { - _touch_irq = touch_irq; - _touch_cs = touch_cs; - pinMode(_touch_cs, OUTPUT); - pinMode(touch_irq, INPUT_PULLUP); - digitalWrite(_touch_cs, 1); - } -} - - -void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { - int dx=0; - int dy=0; -#ifdef ST7789 - if (TFT_REALWIDTH == TFT_REALHEIGHT) - { -#ifdef ROTATE_SCREEN - if (!flipped) { - dy += 80; - } -#else - if (flipped) { - dx += 80; - } -#endif - } -#endif - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - SPI.transfer16(x1+dx); - digitalWrite(_dc, 1); - SPI.transfer16(x2+dx); - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - digitalWrite(_dc, 1); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - return; - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - - SPI.transfer16(x1+dx); - SPI.transfer16(x2+dx); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - -void TFT_T_DMA::begin(void) { - SPI.setMOSI(_mosi); - SPI.setMISO(_miso); - SPI.setSCK(_sclk); - SPI.begin(); - - // Initialize display - if (_rst != 0xff) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - const uint8_t *addr = init_commands; - digitalWrite(_cs, 0); -#ifdef ILI9341 - while (1) { - uint8_t count = *addr++; - if (count-- == 0) break; - - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - - while (count-- > 0) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - } - - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(ILI9341_DISPON); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); -#endif -#ifdef ST7789 - uint8_t numCommands, numArgs; - uint16_t ms; - numCommands = *addr++; // Number of commands to follow - while(numCommands--) { // For each command... - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - numArgs = *addr++; // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs > 1) { // For each argument... - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - numArgs--; - } - - if (numArgs) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - if(ms) { - ms = *addr++; // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - digitalWrite(_cs, 1); - SPI.endTransaction(); - delay(ms); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - } - } - digitalWrite(_cs, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - SPI.endTransaction(); - - cancelled = false; - -#ifdef FLIP_SCREEN - flipscreen(true); -#else - flipscreen(false); -#endif -#ifdef ST7789 - if (TFT_REALWIDTH != TFT_REALHEIGHT) - { - flipscreen(true); - } -#endif -}; - - - -void TFT_T_DMA::flipscreen(bool flip) -{ - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(TFT_MADCTL); - digitalWrite(_dc, 1); - if (flip) { - flipped=true; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB); -#endif -#endif - } - else { - flipped=false; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB); -#endif -#endif - } - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - -boolean TFT_T_DMA::isflipped(void) -{ - return(flipped); -} - - -#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) - - -void TFT_T_DMA::startDMA(void) { - curTransfer = 0; - rstop = 0; - //dmatx.begin(true); - dmatx.attachInterrupt(dmaInterrupt); - setDmaStruct(); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - - digitalWrite(_cs, HIGH); - SPI.begin(); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); - - - LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: - LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX - LPSPIP_TCR = 15; // Framesize 16 Bits - //LPSPIP_FCR = 0; // Fifo Watermark - LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable - LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: - dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); - - dmatx = dmasettings[0]; - digitalWrite(_cs, 0); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - dmatx.enable(); -} - - -void TFT_T_DMA::stopDMA(void) { - rstop = 0; - wait(); - delay(50); - cancelled = false; - dmatx.detachInterrupt(); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - SPI.end(); -#ifdef ST7789 - begin(); -#endif -#ifdef ILI9341 - SPI.begin(); - digitalWrite(_cs, 0); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - SPI.endTransaction(); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); -} - -void TFT_T_DMA::wait(void) { - rstop = 1; - unsigned long m = millis(); - cancelled = true; - while (!rstop) { - if ((millis() - m) > 100) break; - delay(10); - asm volatile("wfi"); - }; - rstop = 0; -} - -int TFT_T_DMA::get_frame_buffer_size(int *width, int *height, int *stride){ - if (width != nullptr) *width = TFT_WIDTH; - if (stride != nullptr) *stride = TFT_WIDTH; - if (height != nullptr) *height = TFT_HEIGHT; - return TFT_REALWIDTH; -} - - -/*********************************************************************************************** - Touch functions - ***********************************************************************************************/ -/* Code based on ... - * - * @file XPT2046.cpp - * @date 19.02.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the XPT2046 driver for Arduino. - */ - -#define ADC_MAX 0x0fff - -void TFT_T_DMA::enableTouchIrq() -{ - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 }; - SPI.transfer((void*)&buf[0],3); - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); -} - -//Default callibration for non flipped -#define TX_MIN 30 -#define TY_MIN 20 -#define TX_MAX 300 -#define TY_MAX 220 - -//Default callibration for flipped -#define TFX_MIN 20 -#define TFY_MIN 25 -#define TFX_MAX 288 -#define TFY_MAX 221 - -static uint16_t txMin; -static uint16_t tyMin; -static uint16_t txMax; -static uint16_t tyMax; - - -void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { - if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) { - txMin = xMin; - tyMin = yMin; - txMax = xMax; - tyMax = yMax; - } - else { - if (flipped) { - txMin = TFX_MIN; - tyMin = TFY_MIN; - txMax = TFX_MAX; - tyMax = TFY_MAX; - } - else { - txMin = TX_MIN; - tyMin = TY_MIN; - txMax = TX_MAX; - tyMax = TY_MAX; - } - } -} - - -void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - if ( TOUCH_ENABLED() ) { - uint16_t x = 0; - uint16_t y = 0; - uint16_t z1 = 0; - uint16_t z2 = 0; - uint8_t i = 0; - int16_t xraw=0, yraw=0; - - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - - for(; i < 15; i++) { - // SPI requirer 32bit aliment - uint8_t buf[12] = { - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00 - }; - SPI.transfer(&buf[0], &buf[0], 12); - y += (buf[1] << 8 | buf[2])>>3; - x += (buf[4] << 8 | buf[5])>>3; - z1 += (buf[7] << 8 | buf[8])>>3; - z2 += (buf[10] << 8 | buf[11])>>3; - } - enableTouchIrq(); - - if(i == 0) { - *oX = 0; - *oY = 0; - *oZ = 0; - } - else { - x /= i; - y /= i; - z1 /= i; - z2 /= i; - } - - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); - int z = z1 + ADC_MAX - z2; - if (flipped) { - xraw = x; - yraw = y; - } else { - xraw = ADC_MAX - x; - yraw = ADC_MAX - y; - } - xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1); - yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1); - - *oX = xraw; - *oY = yraw; - *oZ = z; - } - else - { - *oX = 0; - *oY = 0; - *oZ = 0; - } -} - -void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - readRaw(oX,oY,oZ); - // callibrate ... - if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin); - if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin); - //Serial.print(*oX); - //Serial.print(" "); - //Serial.println(*oY); -} - - -/*********************************************************************************************** - No DMA functions - ***********************************************************************************************/ -void TFT_T_DMA::fillScreenNoDma(uint16_t color) { - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - int i,j; - for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(arx, ary, arx+arw-1, ary+arh-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - bits = *charpt++; - //digitalWrite(_dc, 1); - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - x +=8; -#ifdef ILI9341 - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); -#endif - digitalWrite(_cs, 1); - SPI.endTransaction(); - } - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - - - -/*********************************************************************************************** - DMA functions - ***********************************************************************************************/ -uint16_t * TFT_T_DMA::getLineBuffer(int j) -{ - uint16_t * block=blocks[j>>6]; - return(&block[(j&0x3F)*TFT_REALWIDTH]); -} - -void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) { - uint8_t *buffer=buf; - uint8_t *src; - - int i,j,y=0; - if (width*2 <= TFT_REALWIDTH) { - for (j=0; j>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH]; - for (i=0; i>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x]; - for (i=0; i>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - block=blocks[l>>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt++; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - x +=8; - } -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { - drawSprite(x,y,bitmap, 0,0,0,0); -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) -{ - int bmp_offx = 0; - int bmp_offy = 0; - uint16_t *bmp_ptr; - - int w =*bitmap++; - int h = *bitmap++; - - - if ( (arw == 0) || (arh == 0) ) { - // no crop window - arx = x; - ary = y; - arw = w; - arh = h; - } - else { - if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - int l=ary; - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx]; - bmp_ptr = (uint16_t*)bitmap; - for (int col=0;col -#include -#include -#endif - -#include "tft_t_dma_config.h" - -#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) -#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define R16(rgb) ((rgb>>8)&0xf8) -#define G16(rgb) ((rgb>>3)&0xfc) -#define B16(rgb) ((rgb<<3)&0xf8) - -#define PAL_COLOR_MASK 0xff - -#ifdef LOHRES -#define TFT_WIDTH 240 -#define TFT_REALWIDTH 240 -#else -#define TFT_WIDTH 256 -#define TFT_REALWIDTH 320 -#endif -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - -//#define WIDTH 272 -//#define HEIGHT 228 - -#define LINES_PER_BLOCK 64 -#define NR_OF_BLOCK 4 -#define SCREEN_DMA_NUM_SETTINGS NR_OF_BLOCK - - -#ifdef ILI9341 - -#define ILI9341_NOP 0x00 -#define ILI9341_SWRESET 0x01 -#define ILI9341_RDDID 0x04 -#define ILI9341_RDDST 0x09 - -#define ILI9341_SLPIN 0x10 -#define ILI9341_SLPOUT 0x11 -#define ILI9341_PTLON 0x12 -#define ILI9341_NORON 0x13 - -#define ILI9341_RDMODE 0x0A -#define ILI9341_RDMADCTL 0x0B -#define ILI9341_RDPIXFMT 0x0C -#define ILI9341_RDIMGFMT 0x0D -#define ILI9341_RDSELFDIAG 0x0F - -#define ILI9341_INVOFF 0x20 -#define ILI9341_INVON 0x21 -#define ILI9341_GAMMASET 0x26 -#define ILI9341_DISPOFF 0x28 -#define ILI9341_DISPON 0x29 - -#define ILI9341_CASET 0x2A -#define ILI9341_PASET 0x2B -#define ILI9341_RAMWR 0x2C -#define ILI9341_RAMRD 0x2E - -#define ILI9341_PTLAR 0x30 -#define ILI9341_MADCTL 0x36 -#define ILI9341_VSCRSADD 0x37 -#define ILI9341_PIXFMT 0x3A - -#define ILI9341_FRMCTR1 0xB1 -#define ILI9341_FRMCTR2 0xB2 -#define ILI9341_FRMCTR3 0xB3 -#define ILI9341_INVCTR 0xB4 -#define ILI9341_DFUNCTR 0xB6 - -#define ILI9341_PWCTR1 0xC0 -#define ILI9341_PWCTR2 0xC1 -#define ILI9341_PWCTR3 0xC2 -#define ILI9341_PWCTR4 0xC3 -#define ILI9341_PWCTR5 0xC4 -#define ILI9341_VMCTR1 0xC5 -#define ILI9341_VMCTR2 0xC7 - -#define ILI9341_RDID1 0xDA -#define ILI9341_RDID2 0xDB -#define ILI9341_RDID3 0xDC -#define ILI9341_RDID4 0xDD - -#define ILI9341_GMCTRP1 0xE0 -#define ILI9341_GMCTRN1 0xE1 - -#define ILI9341_MADCTL_MY 0x80 -#define ILI9341_MADCTL_MX 0x40 -#define ILI9341_MADCTL_MV 0x20 -#define ILI9341_MADCTL_ML 0x10 -#define ILI9341_MADCTL_RGB 0x00 -#define ILI9341_MADCTL_BGR 0x08 -#define ILI9341_MADCTL_MH 0x04 - -#define TFT_CASET ILI9341_CASET -#define TFT_PASET ILI9341_PASET -#define TFT_RAMWR ILI9341_RAMWR -#define TFT_MADCTL ILI9341_MADCTL - -#endif - - -#ifdef ST7789 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_RGB 0x00 -#define ST77XX_MADCTL_BGR 0x08 -#define ST77XX_MADCTL_MH 0x04 - -#define TFT_CASET ST7735_CASET -#define TFT_PASET ST7735_RASET -#define TFT_RAMWR ST7735_RAMWR -#define TFT_MADCTL ST7735_MADCTL - -#endif - - - -#ifdef __cplusplus - -class TFT_T_DMA -{ - public: - TFT_T_DMA(uint8_t _CS, uint8_t _DC, uint8_t _RST = 255, uint8_t _MOSI=11, uint8_t _SCLK=13, uint8_t _MISO=12, uint8_t touch_cs=38, uint8_t touch_irq=37); - - void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); - void begin(void); - void flipscreen(bool flip); - boolean isflipped(void); - void startDMA(void); - void stopDMA(); - int get_frame_buffer_size(int *width, int *height, int *stride); - - // Touch screen functions - #define TOUCH_ENABLED() ((_touch_cs != 255) && (_touch_irq != 255)) - bool isTouching(void) { return ((!TOUCH_ENABLED())?false:(digitalRead(_touch_irq) == LOW)); } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax); - - // NoDMA functions - void writeScreenNoDma(const uint16_t *pcolors); - void fillScreenNoDma(uint16_t color); - void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - // DMA functions - uint16_t * getLineBuffer(int j); - void writeScreen(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int y, uint16_t *buf); - void fillScreen(uint16_t color); - void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - protected: - uint8_t _rst, _cs, _dc; - uint8_t _miso, _mosi, _sclk; - uint8_t _touch_irq=255, _touch_cs=255; - bool flipped=false; - - void wait(void); - void enableTouchIrq(); -}; - -#endif -#endif diff --git a/MCUME_teensy41/teensysnes/tft_t_dma_config.h b/MCUME_teensy41/teensysnes/tft_t_dma_config.h deleted file mode 100644 index 354cf74..0000000 --- a/MCUME_teensy41/teensysnes/tft_t_dma_config.h +++ /dev/null @@ -1,14 +0,0 @@ -#include "platform_config.h" - -//#define ST7789 1 -//#define ILI9341 1 - -#define TFT_LINEARINT 1 -#define LINEARINT_HACK 1 - -//#define FLIP_SCREEN 1 -//#define TFT_DEBUG 1 -#if defined(__IMXRT1052__) || defined(__IMXRT1062__) -//#define TFT_STATICFB 1 -#endif - diff --git a/MCUME_teensy41/teensysnes/vga_t_dma.h b/MCUME_teensy41/teensysnes/vga_t_dma.h deleted file mode 100644 index 81a986b..0000000 --- a/MCUME_teensy41/teensysnes/vga_t_dma.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - Wrapping class to extend VGA_T4 to TFT_T_DMA -*/ - -#ifndef _VGA_T_DMAH_ -#define _VGA_T_DMAH_ - -#ifdef __cplusplus -#include -#endif - - -#define RGBVAL16(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) - - - - -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 - -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - - - -#ifdef __cplusplus - -class TFT_T_DMA: public VGA_T4 -{ - public: - // Fake touch screen functions - bool isTouching(void) { return false; } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { } - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { }; - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { } - - // fake DMA functions - void startDMA(void) { }; - void stopDMA(void) { }; - - // fake no DMA functions - void writeScreenNoDma(const vga_pixel *pcolors) { writeScreen(pcolors); } - void fillScreenNoDma(vga_pixel color) { clear(color); } - void drawTextNoDma(int16_t x, int16_t y, const char * text, vga_pixel fgcolor, vga_pixel bgcolor, bool doublesize) { drawText(x,y,text,fgcolor,bgcolor,doublesize); } - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, vga_pixel color) { drawRect(x, y, w, h, color); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap) { drawSprite(x, y, bitmap); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh) { drawSprite(x, y, bitmap, croparx, cropary, croparw, croparh); } -}; - - -#endif -#endif diff --git a/MCUME_teensy41/teensysnes/snes.cpp b/MCUME_teensy41/teensysnes/wrapemu.cpp similarity index 100% rename from MCUME_teensy41/teensysnes/snes.cpp rename to MCUME_teensy41/teensysnes/wrapemu.cpp diff --git a/MCUME_teensy41/teensysnes/snes.h b/MCUME_teensy41/teensysnes/wrapemu.h similarity index 100% rename from MCUME_teensy41/teensysnes/snes.h rename to MCUME_teensy41/teensysnes/wrapemu.h diff --git a/MCUME_teensy41/teensyspeccy/emuapi.cpp b/MCUME_teensy41/teensyspeccy/emuapi.cpp index eb4be06..e128cca 100644 --- a/MCUME_teensy41/teensyspeccy/emuapi.cpp +++ b/MCUME_teensy41/teensyspeccy/emuapi.cpp @@ -5,25 +5,31 @@ extern "C" { #include "iopins.h" } -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#else -#include "tft_t_dma.h" -#endif +#include -#ifdef HAS_USBKEY +#ifdef HAS_USB #include "USBHost_t36.h" // Read this header first for key info USBHost myusb; USBHub hub1(myusb); +#ifdef HAS_USBKEY KeyboardController keyboard1(myusb); USBHIDParser hid1(myusb); MouseController mouse1(myusb); +#endif +#ifdef HAS_USBMIDI MIDIDevice midi1(myusb); #endif +#ifdef HAS_USBJOY +#define COUNT_JOYSTICKS 4 +JoystickController joysticks[COUNT_JOYSTICKS](myusb); +#endif +#endif static bool emu_writeConfig(void); static bool emu_readConfig(void); static bool emu_eraseConfig(void); +static bool emu_writeGfxConfig(char * display_type); +static int emu_readGfxConfig(void); static bool mouseDetected = false; static bool keyboardDetected = false; @@ -34,8 +40,9 @@ static File file; #define MAX_FILES 64 #define AUTORUN_FILENAME "autorun.txt" +#define GFX_CFG_FILENAME "gfxmode.txt" -#define MAX_FILENAME_SIZE 24 +#define MAX_FILENAME_SIZE 34 #define MAX_MENULINES 9 #define TEXT_HEIGHT 16 #define TEXT_WIDTH 8 @@ -53,7 +60,8 @@ static File file; #define MENU_VGA_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) #define MENU_VGA_YOFFSET (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37) -extern TFT_T_DMA tft; +#include "t4_dsp.h" +T4_DSP tft; static int nbFiles=0; static int curFile=0; @@ -65,6 +73,8 @@ static char selected_filename[MAX_FILENAME_SIZE]=""; static char second_selected_filename[MAX_FILENAME_SIZE]=""; static bool menuRedraw=true; static bool autorun=false; +static bool vgahires=false; + static const unsigned short * keys; #ifdef TEECOMPUTER @@ -103,7 +113,7 @@ void emu_printf(int val) void emu_printi(int val) { - Serial.println(val); + Serial.println(val,HEX); } void emu_printh(int val) @@ -158,6 +168,29 @@ void emu_Free(void * pt) free(pt); } +#define SMEMPOOL (0x800000) +EXTMEM static unsigned char slowmem[SMEMPOOL]; +static int slowmempt = 0; + +void * emu_SMalloc(unsigned int size) +{ + void * mem = (void*)&slowmem[slowmempt]; + slowmempt += size; + + if ( slowmempt > SMEMPOOL ) { + mem = NULL; + emu_printf("failure to allocate slow"); + } + else { + emu_printf("could allocate slow static "); + emu_printf(size); + } + return mem; +} + +void emu_SFree(void * pt) +{ +} /******************************** * Input and keyboard ********************************/ @@ -329,6 +362,12 @@ int emu_ReadKeys(void) #endif if ( row & 0x02 ) retval |= MASK_JOY2_BTN; + +#ifdef EXTPAD + if ( sh_pressed ) retval |= MASK_KEY_USER3; + if ( fn_pressed ) retval |= MASK_KEY_USER1; + digitalWrite(KLED, 0); +#else // Handle LED flash uint32_t time_ms=millis(); if ((time_ms-last_t_ms) > 100) { @@ -412,8 +451,9 @@ int emu_ReadKeys(void) if ( key_fn ) retval |= MASK_KEY_USER2; if ( ( key_fn ) && (keymatrix[4] == 0x10 )) retval |= MASK_KEY_USER1; +#endif - if ( (key_fn) && (key_sh) ) + if ( (fn_pressed) && (sh_pressed) ) #else if ( ((retval & (MASK_KEY_USER1+MASK_KEY_USER2)) == (MASK_KEY_USER1+MASK_KEY_USER2)) || (retval & MASK_KEY_USER4 ) ) @@ -453,8 +493,10 @@ int emu_ReadKeys(void) while (true) { ; } -#endif +#endif } + + emu_GetJoystick(); return (retval); } @@ -607,7 +649,7 @@ int emu_setKeymap(int index) { } int emu_GetMouse(int *x, int *y, int *buts) { -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBKEY) if (mouse1.available()) { *buts = mouse1.getButtons(); *x = mouse1.getMouseX(); @@ -620,7 +662,23 @@ int emu_GetMouse(int *x, int *y, int *buts) { return 0; } -#ifdef HAS_USBKEY +int emu_GetJoystick(void) { +#if defined(HAS_USB) && (HAS_USBJOY) + for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) { + if (joysticks[joystick_index].available()) { + uint64_t axis_mask = joysticks[joystick_index].axisMask(); + uint64_t axis_changed_mask = joysticks[joystick_index].axisChangedMask(); + uint32_t buttons = joysticks[joystick_index].getButtons(); + Serial.printf("Joystick(%d): buttons = %x", joystick_index, buttons); + Serial.println(); + } + } + return 1; +#endif + return 0; +} + +#if defined(HAS_USB) && (HAS_USBKEY) void OnPress(auto key) { keyboardDetected = true; @@ -764,7 +822,7 @@ int emu_KeyboardDetected(void) { return (keyboardDetected?1:0); } -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) static unsigned char midiBuffer[16]; static unsigned char midiLastCmd=0; static int midiDataCnt=0; @@ -772,8 +830,7 @@ static int midiCmdNbParam=0; #endif void emu_MidiOnDataReceived(unsigned char value) { - -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) //Serial.println(value, HEX); //10000000 = 128 = note off //10010000 = 144 = note on @@ -941,6 +998,7 @@ void emu_MidiOnDataReceived(unsigned char value) { /******************************** * Menu file loader UI ********************************/ +#ifdef FILEBROWSER static int readNbFiles(void) { int totalFiles = 0; @@ -970,8 +1028,6 @@ static int readNbFiles(void) { return totalFiles; } - - void backgroundMenu(void) { menuRedraw=true; tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00)); @@ -981,11 +1037,13 @@ void backgroundMenu(void) { int handleMenu(uint16_t bClick) { if (autorun) { + toggleMenu(false); + menuRedraw=false; return (ACTION_RUN1); } int action = ACTION_NONE; - if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) ) { + if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) || ( bClick & MASK_KEY_USER2 ) ) { char newpath[MAX_FILENAME_PATH]; strcpy(newpath, selection); strcat(newpath, "/"); @@ -996,17 +1054,31 @@ int handleMenu(uint16_t bClick) File file = SD.open(selection); if (file.isDirectory()) { curFile = 0; - nbFiles = readNbFiles(); + nbFiles = readNbFiles(); + menuRedraw=true; } - else { - action = ACTION_RUN1; + else + { #ifdef TEECOMPUTER - if (key_extmode) { + if ( (key_extmode) || ( key_sh) ) { emu_writeConfig(); } + if ( tft.getMode() < MODE_VGA_320x240) { + if ( bClick & MASK_KEY_USER2 ) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + } + //emu_SwapJoysticks(0); #endif + toggleMenu(false); + menuRedraw=false; + return (ACTION_RUN1); } - menuRedraw=true; } else if ( bClick & MASK_KEY_USER1 ) { menuRedraw=true; @@ -1015,19 +1087,14 @@ int handleMenu(uint16_t bClick) strcat(second_selection, "/"); strcat(second_selection, second_selected_filename); action = ACTION_RUN2; - } - else if ( bClick & MASK_KEY_USER2 ) { - menuRedraw=true; - //action = ACTION_RUN3; - emu_SwapJoysticks(0); - } + } else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) { if (curFile!=0) { menuRedraw=true; curFile--; } } - else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { + else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { if ((curFile-9)>=0) { menuRedraw=true; curFile -= 9; @@ -1042,7 +1109,7 @@ int handleMenu(uint16_t bClick) menuRedraw=true; } } - else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { + else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { if ((curFile<(nbFiles-9)) && (nbFiles)) { curFile += 9; menuRedraw=true; @@ -1099,12 +1166,12 @@ int handleMenu(uint16_t bClick) return (action); } -bool menuActive(void) +int menuActive(void) { - return (menuOn); + return (menuOn?1:0); } -void toggleMenu(bool on) { +void toggleMenu(int on) { if (on) { menuOn=true; backgroundMenu(); @@ -1122,7 +1189,7 @@ char * menuSecondSelection(void) { return (second_selection); } - +#endif /******************************** * OSKB handling @@ -1140,8 +1207,9 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) char c[4] = {' ',0,' ',0}; const char * cpt = str; int i=0; - int fb_width,fb_height; - tft.get_frame_buffer_size(&fb_width, &fb_height); + int fb_width,fb_height,fbstride; + + fbstride = tft.get_frame_buffer_size(&fb_width, &fb_height); int ypos = (bottom?(fb_height-2*8):0); int line = row + (bottom?2:0); while ((c[1] = *cpt++)) @@ -1150,7 +1218,7 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0); else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff); if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff); - tft.drawTextNoDma(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); + tft.drawText(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); i++; } } @@ -1248,7 +1316,7 @@ int handleOSKB(void) { return retval; } -void toggleOSKB(bool forceon) { +void toggleOSKB(int forceon) { if (forceon) { oskbOn = true; drawOSKB(); @@ -1332,6 +1400,17 @@ int emu_FileRead(void * buf, int size, int handler) #endif } +int emu_FileWrite(void * buf, int size, int handler) +{ +// emu_printf("emu_FileWrite"); +// emu_printi(handler); +#ifdef HCFH + return (file.write(buf, size)); +#else + return (getFileHandler(handler).write(buf, size)); +#endif +} + int emu_FileGetc(int handler) { // emu_printf("FileGetc"); // emu_printi(handler); @@ -1404,6 +1483,9 @@ unsigned int emu_FileSize(const char * filepath) emu_printf(filesize); lofile.close(); } + else { + emu_printf("filesize failed"); + } return(filesize); } @@ -1489,6 +1571,48 @@ static bool emu_eraseConfig(void) SD.remove (ROMSDIR "/" AUTORUN_FILENAME); } +static bool emu_writeGfxConfig(char * display_type) +{ + bool retval = false; + SD.remove ("/" GFX_CFG_FILENAME); + if (strcmp(display_type, "VGA")) { + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(display_type, strlen(display_type)) != strlen(display_type)) { + emu_printf("GFX config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + } + return retval; +} + +#define CFG_VGA 0 +#define CFG_ILI 1 +#define CFG_ST 2 + +static int emu_readGfxConfig(void) +{ + int retval = CFG_VGA; // No file = VGA + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + if (filesize == 2) // "ST" + { + retval = CFG_ST; + } + else if (filesize == 3) // "ILI" + { + retval = CFG_ILI; + } + lofile.close(); + } + return retval; +} + /******************************** * File IO compatibility ********************************/ @@ -1670,62 +1794,249 @@ FRESULT f_mkdir (const char* path) /******************************** - * Initialization + * GFX wrapper ********************************/ -void emu_init(void) +static unsigned short palette16[PALETTE_SIZE]; +static IntervalTimer myTimer; +volatile boolean vbl=true; +volatile boolean vgatimervsync=false; +static void (*vblCallback)(void) = nullptr; +static int skip=0; + +static void vblCount() { + if (vbl) { + vbl = false; + } else { + vbl = true; + } +} + +void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) +{ + if (index= MODE_VGA_320x240 ) { + if (vgatimervsync) { + while (vbl==vb) {}; + } + else { + tft.waitSync(); + } + } + else { + while (vbl==vb) {}; + } + if (vblCallback != nullptr) { + vblCallback(); + } +} + +void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride) +{ + if (skip == 0) { + tft.writeScreenPal(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); + } +} +void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLinePal(width,height,line, VBuf, palette16); + } +} + +void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine(width,height,line, VBuf); + } +} + +void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine8(width,height,line, VBuf, palette16); + } +} + +int emu_IsVga(void) +{ + return (tft.getMode() >= MODE_VGA_320x240?1:0); +} + +int emu_IsVgaHires(void) +{ + return (tft.getMode() >= MODE_VGA_640x240?1:0); +} + +int emu_FrameSkip(void) +{ + return skip; +} + + +/******************************** + * AUDIO wrapper +********************************/ +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +AudioPlaySystem mymixer; + +void emu_sndInit() { + Serial.println("sound init"); + mymixer.begin_audio(256, mymixer.snd_Mixer); + mymixer.start(); +} + +void emu_sndPlaySound(int chan, int volume, int freq) +{ + if (chan < 6) { + mymixer.sound(chan, freq, volume); + } + /* + Serial.print(chan); + Serial.print(":" ); + Serial.print(volume); + Serial.print(":" ); + Serial.println(freq); + */ +} + +void emu_sndPlayBuzz(int size, int val) { + mymixer.buzz(size,val); + //Serial.print((val==1)?1:0); + //Serial.print(":"); + //Serial.println(size); +} +#endif + +/******************************** + * Initialization +********************************/ +void emu_init(int hires) { Serial.begin(115200); + vgahires = hires; -#ifdef HAS_USBKEY +#ifdef HAS_USB myusb.begin(); +#ifdef HAS_USBKEY keyboard1.attachPress(OnPress); keyboard1.attachRelease(OnRelease); #endif +#endif - while (!SD.begin(SD_CS)) +#ifdef FILEBROWSER + if (!SD.begin(SD_CS)) { - Serial.println("SD begin failed, retrying..."); - delay(1000); + Serial.println("No SD card detected"); } strcpy(selection,ROMSDIR); - FileHandlersInit(); - nbFiles = readNbFiles(); - - Serial.print("SD initialized, files found: "); Serial.println(nbFiles); +#endif emu_InitJoysticks(); #ifdef SWAP_JOYSTICK - joySwapped = true; + joySwapped = true; #else - joySwapped = false; + joySwapped = false; #endif -#ifdef TEECOMPUTER -#ifndef HAS_T4_VGA - tft.flipscreen(false); -#endif -#endif int keypressed = emu_ReadKeys(); +#ifdef HAS_T4_VGA + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } +#else + int gfx_mode = CFG_VGA; // default +#ifdef FILEBROWSER + gfx_mode = emu_readGfxConfig(); +#endif + // Force VGA if UP pressed + if (keypressed & MASK_JOY2_UP) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("VGA"); +#endif + gfx_mode = CFG_VGA; + } + else { + if (keypressed & MASK_JOY2_LEFT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ST"); +#endif + gfx_mode = CFG_ST; + } + else if (keypressed & MASK_JOY2_RIGHT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ILI"); +#endif + gfx_mode = CFG_ILI; + } + } + if (gfx_mode == CFG_VGA) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + else + { + tft.begin(gfx_mode == CFG_ILI?MODE_TFTILI_320x240:MODE_TFTST_320x240); + } +#endif + if (keypressed & MASK_JOY2_DOWN) { tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) ); tft.drawTextNoDma(64,48, (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); +#ifdef FILEBROWSER emu_eraseConfig(); delay(1000); +#endif } else { +#ifdef FILEBROWSER if (emu_readConfig()) { autorun = true; } +#endif } +#ifdef FILEBROWSER toggleMenu(true); +#endif } -void emu_start(void) +void emu_start(int vblms, void * callback, int forcetimervsync) { + vgatimervsync = forcetimervsync?true:false; + tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); + tft.startRefresh(); + if (callback != nullptr) { + vblCallback = callback; + } + + myTimer.begin(vblCount, vblms); +#ifdef HAS_SND + emu_sndInit(); +#endif usbnavpad = 0; } diff --git a/MCUME_teensy41/teensyspeccy/emuapi.h b/MCUME_teensy41/teensyspeccy/emuapi.h index 2114bae..5dd6130 100644 --- a/MCUME_teensy41/teensyspeccy/emuapi.h +++ b/MCUME_teensy41/teensyspeccy/emuapi.h @@ -2,123 +2,14 @@ #define EMUAPI_H #include "platform_config.h" - -//#define TIMER_REND 1 -#define EXTRA_HEAP 0x10 - -// Title: < > -#define TITLE " SPECTRUM Emulator" -#define ROMSDIR "spec" - -#define emu_Init(ROM) {spec_Init(); spec_Start(ROM);} -#define emu_Step(x) {spec_Step();} -#define emu_Input(x) {spec_Input(x);} - -#define MAX_FILENAME_PATH 64 -#define NB_FILE_HANDLER 4 -#define PALETTE_SIZE 16 -#define VID_FRAME_SKIP 0x3 -#define TFT_VBUFFER_YCROP 0 -#define SINGLELINE_RENDERING 1 - -#define R32(rgb) ((rgb>>16)&0xff) -#define G32(rgb) ((rgb>>8)&0xff) -#define B32(rgb) (rgb & 0xff) +#include "emucfg.h" #define ACTION_NONE 0 -#define ACTION_MAXKBDVAL 16 -#define ACTION_EXITKBD 128 -#define ACTION_RUN1 129 -#define ACTION_RUN2 130 -#define ACTION_RUN3 131 - -#ifdef KEYMAP_PRESENT - -#define keylables_map0_0 (char *)"qwertyuiop\x1a" -#define keylables_map0_1 (char *)" asdfghjkl\x19" -#define keylables_map0_2 (char *)" zxcvbnm,.;/" -#define keylables_map0_3 (char *)" +\x10-" -const unsigned short key_map0[] = { - 'q','w','e','r','t','y','u','i','o','p',127, //lowecase - 0,'a','s','d','f','g','h','j','k','l',10, - 0,'z','x','c','v','b','n','m',',','.',';','/', - 0,0,0,0, - 0,'+',' ','-' - }; - -#define keylables_map1_0 (char *)"QWERTYUIOP@" -#define keylables_map1_1 (char *)" ASDFGHJKL\x19" -#define keylables_map1_2 (char *)" ZXCVBNM<>:?" -#define keylables_map1_3 (char *)" =\x10 " -const unsigned short key_map1[] = { - 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase - 0,'A','S','D','F','G','H','J','K','L',10, - 0,'Z','X','C','V','B','N','M','<','>',':','?', - 154,152,151,153, //U L R D - 0,'=',' ','_' - }; - -#define keylables_map2_0 (char *)"!\"#$% &*()@" -#define keylables_map2_1 (char *)" " -#define keylables_map2_2 (char *)" <>:?" -#define keylables_map2_3 (char *)" =\x10 " -const unsigned short key_map2[] = { - '!','"','#','$','%','^','&','*','(',')','@', // shiftothers - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,'<','>',':','?', - 154,152,151,153, //U L R D - 0,'=',' ','_' - }; - -#define keylables_map3_0 (char *)"1234567890 " -#define keylables_map3_1 (char *)" " -#define keylables_map3_2 (char *)" " -#define keylables_map3_3 (char *)" " - -const unsigned short key_map3[] = { - '1','2','3','4','5','6','7','8','9','0',0, // digit keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 154,152,151,153, //U L R D - 0,0,' ',0 - }; - -#define keylables_map4_0 (char *)" " -#define keylables_map4_1 (char *)" " -#define keylables_map4_2 (char *)" " -#define keylables_map4_3 (char *)" " - -const unsigned short key_map4[] = { - 0,0,0,0,0,0,0,0,0,0,0, // function keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 154,152,151,153, //U L R D - 0,0,' ',0 - }; - -#define keylables_map5_0 (char *)" " -#define keylables_map5_1 (char *)" " -#define keylables_map5_2 (char *)" " -#define keylables_map5_3 (char *)" " - -const unsigned short key_map5[] = { - 0,0,0,0,0,0,0,0,0,0,0, // extra keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 154,152,151,153, //U L R D - 0,0,' ',0 - }; - -const unsigned short matkeys[] = { - 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 - 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 - 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 - 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN - 0x510,0x010,0x110,0x310, // row 4 - }; - -#endif +#define ACTION_RUN1 1 +#define ACTION_RUN2 2 +#define FORCE_VGATIMERVSYNC 1 +#define SUPPORT_HIRES 1 #define MASK_JOY2_RIGHT 0x0001 #define MASK_JOY2_LEFT 0x0002 @@ -135,24 +26,25 @@ const unsigned short matkeys[] = { #define MASK_JOY1_BTN 0x1000 #define MASK_KEY_USER4 0x2000 +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) #ifdef __cplusplus extern "C" { -#else -#define bool unsigned char +extern void emu_init(int hires=0); +extern void emu_start(int vblms, void * callback, int forcetimervsync=0); #endif - -extern void emu_init(void); -extern void emu_start(void); extern void emu_printf(const char * text); extern void emu_printi(int val); extern void emu_printh(int val); extern void * emu_Malloc(unsigned int size); extern void * emu_MallocI(unsigned int size); extern void emu_Free(void * pt); +extern void * emu_SMalloc(unsigned int size); +extern void emu_SFree(void * pt); extern int emu_FileOpen(const char * filepath, const char * mode); extern int emu_FileRead(void * buf, int size, int handler); +extern int emu_FileWrite(void * buf, int size, int handler); extern int emu_FileGetc(int handler); extern int emu_FileSeek(int handler, int seek, int origin); extern int emu_FileTell(int handler); @@ -163,24 +55,23 @@ extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size); extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek); extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index); -extern void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride); -extern void emu_DrawLine(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line); extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line); +extern void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride); extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line); -extern void emu_CopyLine(int width, int height, int ysrc, int ydst); extern void emu_DrawVsync(void); extern int emu_FrameSkip(void); -extern void * emu_LineBuffer(int line); -extern void emu_tweakVideo(int shiftdelta, int numdelta, int denomdelta); +extern int emu_IsVga(void); +extern int emu_IsVgaHires(void); -extern bool menuActive(void); +extern int menuActive(void); extern char * menuSelection(void); extern char * menuSecondSelection(void); -extern void toggleMenu(bool on); +extern void toggleMenu(int on); extern int handleMenu(unsigned short bClick); extern int handleOSKB(void); -extern void toggleOSKB(bool forceon); +extern void toggleOSKB(int forceon); extern void emu_InitJoysticks(void); extern int emu_SwapJoysticks(int statusOnly); @@ -189,6 +80,7 @@ extern int emu_ReadKeys(void); extern int emu_GetPad(void); extern int emu_GetMouse(int *x, int *y, int *buts); extern int emu_MouseDetected(void); +extern int emu_GetJoystick(void); extern int emu_KeyboardDetected(void); extern int emu_ReadAnalogJoyX(int min, int max); extern int emu_ReadAnalogJoyY(int min, int max); diff --git a/MCUME_teensy41/teensyspeccy/emucfg.h b/MCUME_teensy41/teensyspeccy/emucfg.h new file mode 100644 index 0000000..26110ff --- /dev/null +++ b/MCUME_teensy41/teensyspeccy/emucfg.h @@ -0,0 +1,115 @@ +#ifndef EMUCFG_H +#define EMUCFG_H + +#include "wrapemu.h" + +// Title: < > +#define TITLE " SPECTRUM Emulator" +#define ROMSDIR "spec" + +#define emu_Init(ROM) {spec_Init(); spec_Start(ROM);} +#define emu_Step(x) {spec_Step();} +#define emu_Input(x) {spec_Input(x);} + +#define MAX_FILENAME_PATH 64 +#define NB_FILE_HANDLER 4 + +#define PALETTE_SIZE 16 +#define VID_FRAME_SKIP 0x0 +#define TFT_VBUFFER_YCROP 0 +#define SINGLELINE_RENDERING 1 +//#define CUSTOM_SND 1 +//#define TIMER_REND 1 +//#define EXTPAD 1 +#define EXTRA_HEAP 0x10 +#define FILEBROWSER 1 + + +#ifdef KEYMAP_PRESENT + +#define keylables_map0_0 (char *)"qwertyuiop\x1a" +#define keylables_map0_1 (char *)" asdfghjkl\x19" +#define keylables_map0_2 (char *)" zxcvbnm,.;/" +#define keylables_map0_3 (char *)" +\x10-" +const unsigned short key_map0[] = { + 'q','w','e','r','t','y','u','i','o','p',127, //lowecase + 0,'a','s','d','f','g','h','j','k','l',10, + 0,'z','x','c','v','b','n','m',',','.',';','/', + 0,0,0,0, + 0,'+',' ','-' + }; + +#define keylables_map1_0 (char *)"QWERTYUIOP@" +#define keylables_map1_1 (char *)" ASDFGHJKL\x19" +#define keylables_map1_2 (char *)" ZXCVBNM<>:?" +#define keylables_map1_3 (char *)" =\x10 " +const unsigned short key_map1[] = { + 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase + 0,'A','S','D','F','G','H','J','K','L',10, + 0,'Z','X','C','V','B','N','M','<','>',':','?', + 154,152,151,153, //U L R D + 0,'=',' ','_' + }; + +#define keylables_map2_0 (char *)"!\"#$% &*()@" +#define keylables_map2_1 (char *)" " +#define keylables_map2_2 (char *)" <>:?" +#define keylables_map2_3 (char *)" =\x10 " +const unsigned short key_map2[] = { + '!','"','#','$','%','^','&','*','(',')','@', // shiftothers + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 154,152,151,153, //U L R D + 0,'=',' ','_' + }; + +#define keylables_map3_0 (char *)"1234567890 " +#define keylables_map3_1 (char *)" " +#define keylables_map3_2 (char *)" " +#define keylables_map3_3 (char *)" " + +const unsigned short key_map3[] = { + '1','2','3','4','5','6','7','8','9','0',0, // digit keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 154,152,151,153, //U L R D + 0,0,' ',0 + }; + +#define keylables_map4_0 (char *)" " +#define keylables_map4_1 (char *)" " +#define keylables_map4_2 (char *)" " +#define keylables_map4_3 (char *)" " + +const unsigned short key_map4[] = { + 0,0,0,0,0,0,0,0,0,0,0, // function keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 154,152,151,153, //U L R D + 0,0,' ',0 + }; + +#define keylables_map5_0 (char *)" " +#define keylables_map5_1 (char *)" " +#define keylables_map5_2 (char *)" " +#define keylables_map5_3 (char *)" " + +const unsigned short key_map5[] = { + 0,0,0,0,0,0,0,0,0,0,0, // extra keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 154,152,151,153, //U L R D + 0,0,' ',0 + }; + +const unsigned short matkeys[] = { + 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 + 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 + 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 + 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN + 0x510,0x010,0x110,0x310, // row 4 + }; + +#endif + +#endif diff --git a/MCUME_teensy41/teensyspeccy/platform_config.h b/MCUME_teensy41/teensyspeccy/platform_config.h index a27370c..914d152 100644 --- a/MCUME_teensy41/teensyspeccy/platform_config.h +++ b/MCUME_teensy41/teensyspeccy/platform_config.h @@ -4,13 +4,13 @@ #define TEECOMPUTER 1 #ifdef TEECOMPUTER -//#define ILI9341 1 -//#define ST7789 1 -//#define TFTSPI1 1 -#define HAS_T4_VGA 1 +#define TFTSPI1 1 +//#define HAS_T4_VGA 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 -#define INVX 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 #define PT8211 1 #else @@ -19,7 +19,11 @@ //#define INVX 1 #define INVY 1 #define HAS_SND 1 +#define HAS_USB 1 #define HAS_USBKEY 1 +//#define HAS_USBMOUSE 1 +//#define HAS_USBMIDI 1 +#define PT8211 1 #endif diff --git a/MCUME_teensy41/teensyspeccy/t4_dsp.cpp b/MCUME_teensy41/teensyspeccy/t4_dsp.cpp new file mode 100644 index 0000000..43301fa --- /dev/null +++ b/MCUME_teensy41/teensyspeccy/t4_dsp.cpp @@ -0,0 +1,1774 @@ +/* + TFT/VGA driver + DMA TFT driver based on C64 ILI9341 dma driver from Frank Bösing, 2017 +*/ + +#include "T4_DSP.h" + +#include +#include + +#include "font8x8.h" + +// TFT constants and variables +#define TFT_LINEARINT 1 +#define LINEARINT_HACK 1 +#define DMA_LINES_PER_BLOCK 64 +#define DMA_NUM_SETTINGS 4 + +#define TFT_SWRESET 0x01 +#define TFT_SLPOUT 0x11 +#define TFT_INVON 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_MADCTL 0x36 +#define TFT_PIXFMT 0x3A +#define TFT_MADCTL_MY 0x80 +#define TFT_MADCTL_MX 0x40 +#define TFT_MADCTL_MV 0x20 +#define TFT_MADCTL_ML 0x10 +#define TFT_MADCTL_RGB 0x00 +#define TFT_MADCTL_BGR 0x08 +#define TFT_MADCTL_MH 0x04 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) +//#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) +//#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) +//#define R16(rgb) ((rgb>>8)&0xf8) +//#define G16(rgb) ((rgb>>3)&0xfc) +//#define B16(rgb) ((rgb<<3)&0xf8) + +// LPSPI4 = SPI0 in Teensy 4.0 +// LPSPI3 = SPI1 in Teensy 4.0 +// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) + +#ifdef TFTSPI1 +#define SPI SPI1 +#define LPSPIP_TDR LPSPI3_TDR +#define LPSPIP_CR LPSPI3_CR +#define LPSPIP_CFGR1 LPSPI3_CFGR1 +#define LPSPIP_TCR LPSPI3_TCR +#define LPSPIP_DER LPSPI3_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX +#else +#define LPSPIP_TDR LPSPI4_TDR +#define LPSPIP_CR LPSPI4_CR +#define LPSPIP_CFGR1 LPSPI4_CFGR1 +#define LPSPIP_TCR LPSPI4_TCR +#define LPSPIP_DER LPSPI4_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX +#endif + +#define SPICLOCK 60000000 +#define SPI_MODE SPI_MODE0 + +// VGA constants and macros +typedef uint8_t vga_pixel; +#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) + +static DMASetting dmasettings[DMA_NUM_SETTINGS]; +static DMAChannel dmatx; +static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K +static volatile uint8_t rstop = 0; +static volatile bool cancelled = false; +static volatile uint8_t curTransfer = 0; +static uint8_t nbTransfer = 0; +static uint16_t * tft_buffer; +static int tft_width; +static int tft_height; +static int tft_stride; + +#define DELAY_MASK 0x80 +PROGMEM static const uint8_t init_commands[] = { + 1+DELAY_MASK, TFT_SWRESET, 150, + 1+DELAY_MASK, TFT_SLPOUT, 255, + 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, + 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, + 1, TFT_INVON, + 1, TFT_DISPON, + 0 +}; + +// VGA constants and variables +// Objective: +// generates VGA signal fully in hardware with as little as possible CPU help + +// Principle: +// QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) +// 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate +// RGB out, combined to create 8bits(/12bits) output. + +// Note: +// - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels +// - experimental resolution: 352x240,352x480 +// - experimental resolution: 512x240,512x480 (not stable) +// - video memory is allocated using malloc in T4 heap +// - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing +// but tried to be compensated by pixel shifting +// - Default is 8bits RRRGGGBB (332) +// But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! +// - Only ok at 600MHz else some disturbances visible + + + +#define TOP_BORDER 40 +#define PIN_HBLANK 15 + +#define PIN_R_B2 33 +#define PIN_R_B1 4 +#define PIN_R_B0 3 +#define PIN_G_B2 2 +#define PIN_G_B1 13 +#define PIN_G_B0 11 +#define PIN_B_B1 12 +#define PIN_B_B0 10 + + +#define DMA_HACK 0x80 + +#define R16(rgb) ((rgb>>8)&0xf8) +#define G16(rgb) ((rgb>>3)&0xfc) +#define B16(rgb) ((rgb<<3)&0xf8) + +// VGA 640x480@60Hz +// Screen refresh rate 60 Hz +// Vertical refresh 31.46875 kHz +// Pixel freq. 25.175 MHz +// +// Visible area 640 25.422045680238 us +// Front porch 16 0.63555114200596 us +// Sync pulse 96 3.8133068520357 us +// Back porch 48 1.9066534260179 us +// Whole line 800 31.777557100298 us + +#define frame_freq 60.0 // Hz +#define line_freq 31.46875 // KHz +#define pix_freq (line_freq*800) // KHz (25.175 MHz) + +// pix_period = 39.7ns +// H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) +#define frontporch_pix 20 //16 +#define backporch_pix 44 //48 + +// Flexio Clock +// PLL3 SW CLOCK (3) => 480 MHz +// PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) +#define FLEXIO_CLK_SEL_PLL3 3 +#define FLEXIO_CLK_SEL_PLL5 2 + +/* Set video PLL */ +// There are /1, /2, /4, /8, /16 post dividers for the Video PLL. +// The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, +// and CCM_ANALOG_MISC2 register sets according to the following equation. +// PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + +// nfact: +// This field controls the PLL loop divider. +// Valid range for DIV_SELECT divider value: 27~54. + +#define POST_DIV_SELECT 2 + +// Full buffer including back/front porch +static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; +static uint32_t dstbuffer __attribute__((aligned(32))); + +// Visible vuffer +static vga_pixel * vga_buffer; +static int vga_width; +static int vga_height; +static int vga_stride; + +static int maxpixperline; +static int left_border; +static int right_border; +static int line_double; +static int pix_shift; +static int ref_div_select; +static int ref_freq_num; +static int ref_freq_denom; +static int ref_pix_shift; +static int combine_shiftreg; + +#ifdef DEBUG +static uint32_t ISRTicks_prev = 0; +volatile uint32_t ISRTicks = 0; +#endif + +uint8_t T4_DSP::_rst; +uint8_t T4_DSP::_cs; +uint8_t T4_DSP::_dc; +uint8_t T4_DSP::_mosi; +uint8_t T4_DSP::_sclk; +uint8_t T4_DSP::_vsync_pin = -1; +DMAChannel T4_DSP::flexio1DMA; +DMAChannel T4_DSP::flexio2DMA; + +static volatile uint32_t VSYNC = 0; +static volatile uint32_t currentLine=0; +#define NOP asm volatile("nop\n\t"); +static gfx_mode_t gfxmode = MODE_UNDEFINED; + + +FASTRUN void T4_DSP::TFT_isr(void) { + dmatx.clearInterrupt(); + curTransfer++; + if (curTransfer >= nbTransfer) { + curTransfer = 0; + if (cancelled) { + dmatx.disable(); + rstop = 1; + } + } + arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); +} + +FASTRUN void T4_DSP::QT3_isr(void) { + TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); + TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); + + cli(); + + // V-PULSE + if (currentLine > 0) { + digitalWrite(_vsync_pin, 1); + VSYNC = 0; + } else { + digitalWrite(_vsync_pin, 0); + VSYNC = 1; + } + + currentLine++; + currentLine = currentLine % 525; + + + uint32_t y = (currentLine - TOP_BORDER) >> line_double; + // Visible area + + if (y >= 0 && y < vga_height) { + // Disable DMAs + //DMA_CERQ = flexio2DMA.channel; + //DMA_CERQ = flexio1DMA.channel; + + // Setup source adress + // Aligned 32 bits copy + unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; + flexio2DMA.TCD->SADDR = p; + if (pix_shift & DMA_HACK) + { + // Unaligned copy + uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; + flexio1DMA.TCD->SADDR = p2; + } + else { + p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 + flexio1DMA.TCD->SADDR = p; + } + + // Enable DMAs + //flexio2DMA.enable(); + //flexio1DMA.enable(); + DMA_SERQ = flexio2DMA.channel; + DMA_SERQ = flexio1DMA.channel; + arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); + } + sei(); + +#ifdef DEBUG + ISRTicks++; +#endif + asm volatile("dsb"); +} + +static void setDmaStruct() { + uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; + uint16_t * fb = (uint16_t*)malloc(remaining); + tft_buffer = fb; + tft_width = TFT_WIDTH; + tft_height = TFT_HEIGHT; + tft_stride = TFT_WIDTH; + uint16_t col=RGBVAL16(0x00,0x00,0x00); + int i=0; + while (remaining > 0) { + int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); + blocks[i] = fb; + for (int j=0;jATTR_DST = 1; + dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); + dmasettings[i].interruptAtCompletion(); + fb += len/2; + remaining -= len; + i++; + } + dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); + nbTransfer = i; +} + +static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 +{ +//if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; + CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE + | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 + | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); + CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; + CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock + const int div_post_pll = 1; // other values: 2,4 + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass +} + +T4_DSP::T4_DSP() +{ + _cs = TFT_CS; + _dc = TFT_DC; + _rst = TFT_RST; + _mosi = TFT_MOSI; + _sclk = TFT_SCLK; + pinMode(_dc, OUTPUT); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, 1); + digitalWrite(_dc, 1); + _vsync_pin = 8; +} + + +void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { + int dx=0; + int dy=0; + digitalWrite(_dc, 0); + SPI.transfer(TFT_CASET); + digitalWrite(_dc, 1); + SPI.transfer16(x1+dx); + digitalWrite(_dc, 1); + SPI.transfer16(x2+dx); + digitalWrite(_dc, 0); + SPI.transfer(TFT_PASET); + digitalWrite(_dc, 1); + SPI.transfer16(y1+dy); + digitalWrite(_dc, 1); + SPI.transfer16(y2+dy); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + return; +} + +void T4_DSP::tft_setup(bool isST) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + // RESET if reset pin defined + if (_rst != 0xff) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + const uint8_t *addr = init_commands; + uint8_t count; + digitalWrite(_cs, 0); + while (count = *addr++) { + uint8_t command = *addr++; + if ( (command == TFT_INVON) && (!isST) ) { + // Skip TFT_INVON for ILI + } + else { + digitalWrite(_dc, 0); // command + SPI.transfer(command); + uint16_t ms = count & DELAY_MASK; + count &= ~DELAY_MASK; + while (--count > 0) { // data + uint8_t data = *addr++; + if ( (command == TFT_MADCTL) && (isST) ) { + data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; + } + digitalWrite(_dc, 1); + SPI.transfer(data); + } + if (ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + digitalWrite(_cs, 1); + SPI.endTransaction(); + delay(2); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + } + } + } + digitalWrite(_cs, 1); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + SPI.endTransaction(); + /* + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_dc, 0); + digitalWrite(_cs, 0); + SPI.transfer(TFT_MADCTL); + digitalWrite(_dc, 1); + SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); + // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); + digitalWrite(_cs, 1); + SPI.endTransaction(); + */ + cancelled = false; +} + +// display VGA image +gfx_error_t T4_DSP::begin(gfx_mode_t mode) +{ + uint32_t flexio_clock_div; + combine_shiftreg = 0; +// int div_select = 49; +// int num = 135; +// int denom = 100; + int div_select = 20; + int num = 9800; + int denom = 10000; + int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; + int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; + set_videoClock(div_select,num,denom,true); + +#ifdef DEBUG + Serial.println(mode); + Serial.println("mode"); +#endif + + switch(mode) + { + case MODE_TFTILI_320x240: +#ifdef DEBUG + Serial.println("TFTILI_320x240"); +#endif + tft_setup(false); + gfxmode = mode; + break; + case MODE_TFTST_320x240: +#ifdef DEBUG + Serial.println("TFTST_320x240"); +#endif + tft_setup(true); + gfxmode = mode; + break; + + case MODE_VGA_320x240: +#ifdef DEBUG + Serial.println("VGA_320x240"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_320x480: +#ifdef DEBUG + Serial.println("VGA_320x480"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_640x240: +#ifdef DEBUG + Serial.println("VGA_640x240"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/pix_freq; + line_double = 1; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_640x480: +#ifdef DEBUG + Serial.println("VGA_640x480"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = (flexio_freq/pix_freq); + line_double = 0; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_512x240: +#ifdef DEBUG + Serial.println("VGA_512x240"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 1; + pix_shift = 0; + break; + + case MODE_VGA_512x480: +#ifdef DEBUG + Serial.println("VGA_512x480"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 0; + pix_shift = 0; + break; + + case MODE_VGA_352x240: +#ifdef DEBUG + Serial.println("VGA_352x240"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_352x480: +#ifdef DEBUG + Serial.println("VGA_352x480"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + } + + if (mode >= MODE_VGA_320x240) + { + if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { + fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); + digitalWrite(_cs, 0); + digitalWrite(_dc, 0); + SPI.transfer(TFT_DISPOFF); + digitalWrite(_cs, 1); + delay(20); + digitalWrite(_cs, 0); + digitalWrite(_cs, 1); + } + gfxmode = mode; + + maxpixperline = vga_stride; + // Save param for tweek adjustment + ref_div_select = div_select; + ref_freq_num = num; + ref_freq_denom = denom; + ref_pix_shift = pix_shift; + +#ifdef DEBUG + Serial.println("frequency"); + Serial.println(flexio_freq); + Serial.println("div"); + Serial.println(flexio_freq/pix_freq); +#endif + + pinMode(_vsync_pin, OUTPUT); + pinMode(PIN_HBLANK, OUTPUT); + + /* Basic pin setup FlexIO1 */ + pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 + pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 + pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 + pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 + /* Basic pin setup FlexIO2 */ + pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 + pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 + pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 + pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 + + /* High speed and drive strength configuration */ + *(portControlRegister(PIN_G_B2)) = 0xFF; + *(portControlRegister(PIN_R_B0)) = 0xFF; + *(portControlRegister(PIN_R_B1)) = 0xFF; + *(portControlRegister(PIN_R_B2)) = 0xFF; + *(portControlRegister(PIN_B_B0)) = 0xFF; + *(portControlRegister(PIN_B_B1)) = 0xFF; + *(portControlRegister(PIN_G_B0)) = 0xFF; + *(portControlRegister(PIN_G_B1)) = 0xFF; + + /* Set clock for FlexIO1 and FlexIO2 */ + CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) + | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); + CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) + | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); + + + /* Set up pin mux FlexIO1 */ + *(portConfigRegister(PIN_G_B2)) = 0x14; + *(portConfigRegister(PIN_R_B0)) = 0x14; + *(portConfigRegister(PIN_R_B1)) = 0x14; + *(portConfigRegister(PIN_R_B2)) = 0x14; + /* Set up pin mux FlexIO2 */ + *(portConfigRegister(PIN_B_B0)) = 0x14; + *(portConfigRegister(PIN_B_B1)) = 0x14; + *(portConfigRegister(PIN_G_B0)) = 0x14; + *(portConfigRegister(PIN_G_B1)) = 0x14; + + /* Enable the clock */ + CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + /* Enable the FlexIO with fast access */ + FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + + uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; + uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; + + /* Shifter 0 registers for FlexIO2 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 + inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter + stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled + startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable + timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 + timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock + pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output + pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity + shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode + /* Shifter 0 registers for FlexIO1 */ + FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + /* Shifter 0 registers for FlexIO1 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 + FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + if (combine_shiftreg) { + pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled + FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + } + /* Timer 0 registers for FlexIO2 */ + timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset + timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output + timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset + timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare + timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert + stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled + startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled + if (combine_shiftreg) { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag + } + else { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag + } + triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low + triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected + pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled + //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 + //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high + timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode + // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) + + int shifts_per_transfer; + if (combine_shiftreg) { + shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 + } + else { + shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 + } + FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); + /* Timer 0 registers for FlexIO1 */ + FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); +#ifdef DEBUG + Serial.println("FlexIO setup complete"); +#endif + + /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ + if (combine_shiftreg) { + FLEXIO2_SHIFTSDEN |= (1<<1); + FLEXIO1_SHIFTSDEN |= (1<<1); + } + else { + FLEXIO2_SHIFTSDEN |= (1<<0); + FLEXIO1_SHIFTSDEN |= (1<<0); + } + /* Disable DMA channel so it doesn't start transferring yet */ + flexio1DMA.disable(); + flexio2DMA.disable(); + /* Set up DMA channel to use Shifter 0 trigger */ + flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); + flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); + + + if (combine_shiftreg) { + flexio2DMA.TCD->NBYTES = 8; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 8; + flexio2DMA.TCD->CITER = maxpixperline / 8; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + flexio1DMA.TCD->NBYTES = 8; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 8; + flexio1DMA.TCD->CITER = maxpixperline / 8; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Setup DMA2 Flexio2 copy + flexio2DMA.TCD->NBYTES = 4; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 4; + flexio2DMA.TCD->CITER = maxpixperline / 4; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + // Setup DMA1 Flexio1 copy + // Use pixel shift to avoid color smearing? + if (pix_shift & DMA_HACK) + { + if (pix_shift & 0x3 == 0) { + // Aligned 32 bits copy (32bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Unaligned (source) 32 bits copy (8bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 1; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion + } + } + else + { + // Aligned 32 bits copy + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + } + +#ifdef DEBUG + Serial.println("DMA setup complete"); +#endif + + // enable clocks for QTIMER3: generates the 15KHz for hsync + // Pulse: + // low : 3.8133 us => 569x6.7ns + // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) + // (OLD TEST) + // (4us low, 28us high => 32us) + // (597x6.7ns for 4us) + // (4179x6.7ns for 28us) + CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 + //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 + + #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz + #define MARGIN_D 1000 + + TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer + // Invert output pin as we want the interupt on rising edge + TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) + TMR3_CNTR3 = 0; + TMR3_LOAD3 = 0; + + /* Inverted timings */ + unsigned long long cpu_freq = F_CPU; + unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; + int rate2 = rate; + + int substract = 1; + if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { + substract=5; + rate2=1652; + } + + #ifdef DEBUG + Serial.print("MARGIN_N is: "); + Serial.println(rate2, DEC); + Serial.print("SUBSTRACT is: "); + Serial.println(substract, DEC); +#endif + TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; + TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; + /* + TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; + */ + TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on + TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), + // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) + //configure Teensy pin Compare output + IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 + attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function + NVIC_ENABLE_IRQ(IRQ_QTIMER3); +#ifdef DEBUG + Serial.println("QTIMER3 setup complete"); + Serial.print("V-PIN is "); + Serial.println(_vsync_pin); +#endif + + /* initialize gfx buffer */ + if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift + if (gfxbuffer == NULL) return(GFX_ERROR); +#ifdef DEBUG + Serial.println("Memory allocated"); +#endif + + memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); + vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; +#ifdef DEBUG + Serial.println(vga_stride); + Serial.println(vga_height); + Serial.println("Screen cleared"); +#endif + } + + return(GFX_OK); +} + +gfx_mode_t T4_DSP::getMode(void) +{ + return gfxmode; +} + +void T4_DSP::startRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + curTransfer = 0; + rstop = 0; + //dmatx.begin(true); + dmatx.attachInterrupt(TFT_isr); + setDmaStruct(); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + + digitalWrite(_cs, HIGH); + SPI.begin(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + + LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: + LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX + LPSPIP_TCR = 15; // Framesize 16 Bits + //LPSPIP_FCR = 0; // Fifo Watermark + LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable + LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: + dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); + + dmatx = dmasettings[0]; + digitalWrite(_cs, 0); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + dmatx.enable(); + } +} + + +void T4_DSP::stopRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + rstop = 1; + unsigned long m = millis(); + cancelled = true; + while (!rstop) { + if ((millis() - m) > 100) break; + delay(10); + asm volatile("wfi"); + }; + rstop = 0; + delay(50); + cancelled = false; + dmatx.detachInterrupt(); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + SPI.end(); +#ifdef ST7789 +// begin(gfxmode); +#endif + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + } +} + +int T4_DSP::get_frame_buffer_size(int *width, int *height) { + if (gfxmode < MODE_VGA_320x240) { + if (width != nullptr) *width = tft_width; + if (height != nullptr) *height = tft_height; + return tft_stride; + } + else { + if (width != nullptr) *width = vga_width; + if (height != nullptr) *height = vga_height; + return vga_stride; + } +} + +void T4_DSP::waitSync() +{ + if (gfxmode >= MODE_VGA_320x240) { + while (VSYNC == 0) {}; + } +} + +void T4_DSP::waitLine(int line) +{ + if (gfxmode >= MODE_VGA_320x240) { + while (currentLine != line) {}; + } +} + +/*********************************************************************************************** + No DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreenNoDma(uint16_t color) { + if (gfxmode < MODE_VGA_320x240) { + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + int i,j; + for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(arx, ary, arx+arw-1, ary+arh-1); + bitmap = bitmap + bmp_offy*w + bmp_offx; + for (int row=0;row> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + bits = *charpt++; + //digitalWrite(_dc, 1); + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + x +=8; + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + else { + drawText(x, y, text, fgcolor, bgcolor, doublesize); + } +} + + +/*********************************************************************************************** + DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreen(uint16_t color) { + int i,j; + if (gfxmode < MODE_VGA_320x240) { + for (j=0; j> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + dst=&tft_buffer[l*tft_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + x +=8; + } + } + else { + vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); + vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); + vga_pixel * dst; + while ((c = *text++)) { + const unsigned char * charpt=&font8x8[c][0]; + int l=y; + for (int i=0;i<8;i++) + { + unsigned char bits; + if (doublesize) { + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + x +=8; + } + } +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { + drawSprite(x,y,bitmap, 0,0,0,0); +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) +{ + int bmp_offx = 0; + int bmp_offy = 0; + uint16_t *bmp_ptr; + int w =*bitmap++; + int h = *bitmap++; + if ( (arw == 0) || (arh == 0) ) { + // no crop window + arx = x; + ary = y; + arw = w; + arh = h; + } + else { + if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + int l=ary; + bitmap = bitmap + bmp_offy*w + bmp_offx; + + if (gfxmode < MODE_VGA_320x240) { + for (int row=0;row tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]; + pos +=step; + } + #endif + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i 2) ) y += (tft_height-height)/2; + uint16_t * dst=&tft_buffer[y*tft_stride]; + if (width > tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]]; + pos +=step; + } +#endif + } + else if ((width*2) == tft_width) { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]]; + *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i tft_width) { + int step = ((width << 8)/tft_width); + int pos = 0; + for (int i=0; i> 8]]; + pos +=step; + } + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = pix; + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i +#include +#endif + +#include "platform_config.h" +#include "iopins.h" + + + +#ifndef TFT_WIDTH +#define TFT_WIDTH 320 +#endif +#define TFT_REALWIDTH 320 + +#ifndef TFT_HEIGHT +#define TFT_HEIGHT 240 +#endif +#define TFT_REALHEIGHT 240 + + +typedef enum gfx_mode_t +{ + MODE_UNDEFINED = 0, + MODE_TFTILI_320x240 = 1, + MODE_TFTST_320x240 = 2, + MODE_VGA_320x240 = 3, + MODE_VGA_320x480 = 4, + MODE_VGA_352x240 = 5, + MODE_VGA_352x480 = 6, + MODE_VGA_512x240 = 7, + MODE_VGA_512x480 = 8, + MODE_VGA_640x240 = 9, + MODE_VGA_640x480 = 10 +} gfx_mode_t; + +typedef enum gfx_error_t +{ + GFX_OK = 0, + GFX_ERROR = -1 +} gfx_error_t; + + +#ifdef __cplusplus + +class T4_DSP +{ + public: + T4_DSP(); + + gfx_error_t begin(gfx_mode_t mode); + gfx_mode_t getMode(void); + void startRefresh(void); + void stopRefresh(); + + int get_frame_buffer_size(int *width, int *height); + void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); + + // wait next Vsync + void waitSync(); + void waitLine(int line); + + // NoDMA functions + void fillScreenNoDma(uint16_t color); + void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + // DMA functions + void fillScreen(uint16_t color); + void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + void writeLine(int width, int height, int y, uint16_t *buf); + void writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + void writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16); + void writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + + protected: + static uint8_t _rst, _cs, _dc; + static uint8_t _mosi, _sclk; + static uint8_t _vsync_pin; + static DMAChannel flexio1DMA; + static DMAChannel flexio2DMA; + void tft_setup(bool isST); + static void TFT_isr(void); + static void QT3_isr(void); +}; + +#endif +#endif diff --git a/MCUME_teensy41/teensyspeccy/teensyspeccy.ino b/MCUME_teensy41/teensyspeccy/teensyspeccy.ino index 7de7b98..4684570 100644 --- a/MCUME_teensy41/teensyspeccy/teensyspeccy.ino +++ b/MCUME_teensy41/teensyspeccy/teensyspeccy.ino @@ -3,135 +3,16 @@ extern "C" { #include "emuapi.h" } -extern "C" { -#include "spec.h" -} - -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -TFT_T_DMA tft; -#else -#include "tft_t_dma.h" -TFT_T_DMA tft = TFT_T_DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, TFT_TOUCH_CS, TFT_TOUCH_INT); -#endif - -bool vgaMode = false; - -static unsigned char palette8[PALETTE_SIZE]; -static unsigned short palette16[PALETTE_SIZE]; -static IntervalTimer myTimer; -volatile boolean vbl=true; -static int skip=0; -static elapsedMicros tius; - -static void vblCount() { - if (vbl) { - vbl = false; - } else { - vbl = true; - } -} - -void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) -{ - if (index>8, - 320 & 0xFF, // YEND = 320 - ST7735_INVON , DELAY, // 7: hack - 10, - ST7735_NORON , DELAY, // 8: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 9: Main screen turn on, no args, w/delay - 255 -#endif -}; - -static void dmaInterrupt() { - dmatx.clearInterrupt(); - curTransfer++; - if (curTransfer >= nbTransfer) { - curTransfer = 0; - if (cancelled) { - dmatx.disable(); - rstop = 1; - } - } - arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2); -} - -static void setDmaStruct() { - uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; - int i=0; - uint16_t col=RGBVAL16(0x00,0x00,0x00);; - while (remaining > 0) { - uint16_t * fb = blocks[i]; - int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining); -#ifdef TFT_DEBUG - Serial.println((unsigned long)blocks[i]); - Serial.println(remaining); -#endif - switch (i) { - case 0: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb0[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0x00); -#endif - break; - case 1: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb1[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0xff); -#endif - break; - case 2: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb2[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0x00,0xff); -#endif - break; - case 3: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb3[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0xff,0x00,0xff); -#endif - break; - } - blocks[i] = fb; - if (blocks[i] == 0) { - Serial.print("ILI9341 allocaltion failed for block "); - Serial.println(i); - delay(10000); - } - - for (int j=0;jATTR_DST = 1; - dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); - dmasettings[i].interruptAtCompletion(); - remaining -= len; - i++; - } - dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); - nbTransfer = i; -#ifdef TFT_DEBUG - Serial.println(nbTransfer); -#endif -} - - -TFT_T_DMA::TFT_T_DMA(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso, uint8_t touch_cs, uint8_t touch_irq) -{ - _cs = cs; - _dc = dc; - _rst = rst; - _mosi = mosi; - _sclk = sclk; - _miso = miso; - pinMode(_dc, OUTPUT); - pinMode(_cs, OUTPUT); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); - if ( (touch_cs != 255) && (touch_irq != 255) ) { - _touch_irq = touch_irq; - _touch_cs = touch_cs; - pinMode(_touch_cs, OUTPUT); - pinMode(touch_irq, INPUT_PULLUP); - digitalWrite(_touch_cs, 1); - } -} - - -void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { - int dx=0; - int dy=0; -#ifdef ST7789 - if (TFT_REALWIDTH == TFT_REALHEIGHT) - { -#ifdef ROTATE_SCREEN - if (!flipped) { - dy += 80; - } -#else - if (flipped) { - dx += 80; - } -#endif - } -#endif - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - SPI.transfer16(x1+dx); - digitalWrite(_dc, 1); - SPI.transfer16(x2+dx); - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - digitalWrite(_dc, 1); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - return; - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - - SPI.transfer16(x1+dx); - SPI.transfer16(x2+dx); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - -void TFT_T_DMA::begin(void) { - SPI.setMOSI(_mosi); - SPI.setMISO(_miso); - SPI.setSCK(_sclk); - SPI.begin(); - - // Initialize display - if (_rst != 0xff) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - const uint8_t *addr = init_commands; - digitalWrite(_cs, 0); -#ifdef ILI9341 - while (1) { - uint8_t count = *addr++; - if (count-- == 0) break; - - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - - while (count-- > 0) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - } - - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(ILI9341_DISPON); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); -#endif -#ifdef ST7789 - uint8_t numCommands, numArgs; - uint16_t ms; - numCommands = *addr++; // Number of commands to follow - while(numCommands--) { // For each command... - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - numArgs = *addr++; // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs > 1) { // For each argument... - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - numArgs--; - } - - if (numArgs) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - if(ms) { - ms = *addr++; // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - digitalWrite(_cs, 1); - SPI.endTransaction(); - delay(ms); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - } - } - digitalWrite(_cs, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - SPI.endTransaction(); - - cancelled = false; - -#ifdef FLIP_SCREEN - flipscreen(true); -#else - flipscreen(false); -#endif -#ifdef ST7789 - if (TFT_REALWIDTH != TFT_REALHEIGHT) - { - flipscreen(true); - } -#endif -}; - - - -void TFT_T_DMA::flipscreen(bool flip) -{ - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(TFT_MADCTL); - digitalWrite(_dc, 1); - if (flip) { - flipped=true; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB); -#endif -#endif - } - else { - flipped=false; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB); -#endif -#endif - } - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - -boolean TFT_T_DMA::isflipped(void) -{ - return(flipped); -} - - -#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) - - -void TFT_T_DMA::startDMA(void) { - curTransfer = 0; - rstop = 0; - //dmatx.begin(true); - dmatx.attachInterrupt(dmaInterrupt); - setDmaStruct(); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - - digitalWrite(_cs, HIGH); - SPI.begin(); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); - - - LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: - LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX - LPSPIP_TCR = 15; // Framesize 16 Bits - //LPSPIP_FCR = 0; // Fifo Watermark - LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable - LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: - dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); - - dmatx = dmasettings[0]; - digitalWrite(_cs, 0); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - dmatx.enable(); -} - - -void TFT_T_DMA::stopDMA(void) { - rstop = 0; - wait(); - delay(50); - cancelled = false; - dmatx.detachInterrupt(); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - SPI.end(); -#ifdef ST7789 - begin(); -#endif -#ifdef ILI9341 - SPI.begin(); - digitalWrite(_cs, 0); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - SPI.endTransaction(); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); -} - -void TFT_T_DMA::wait(void) { - rstop = 1; - unsigned long m = millis(); - cancelled = true; - while (!rstop) { - if ((millis() - m) > 100) break; - delay(10); - asm volatile("wfi"); - }; - rstop = 0; -} - -int TFT_T_DMA::get_frame_buffer_size(int *width, int *height){ - if (width != nullptr) *width = TFT_REALWIDTH; - if (height != nullptr) *height = TFT_REALHEIGHT; - return TFT_REALWIDTH; -} - - -/*********************************************************************************************** - Touch functions - ***********************************************************************************************/ -/* Code based on ... - * - * @file XPT2046.cpp - * @date 19.02.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the XPT2046 driver for Arduino. - */ - -#define ADC_MAX 0x0fff - -void TFT_T_DMA::enableTouchIrq() -{ - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 }; - SPI.transfer((void*)&buf[0],3); - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); -} - -//Default callibration for non flipped -#define TX_MIN 30 -#define TY_MIN 20 -#define TX_MAX 300 -#define TY_MAX 220 - -//Default callibration for flipped -#define TFX_MIN 20 -#define TFY_MIN 25 -#define TFX_MAX 288 -#define TFY_MAX 221 - -static uint16_t txMin; -static uint16_t tyMin; -static uint16_t txMax; -static uint16_t tyMax; - - -void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { - if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) { - txMin = xMin; - tyMin = yMin; - txMax = xMax; - tyMax = yMax; - } - else { - if (flipped) { - txMin = TFX_MIN; - tyMin = TFY_MIN; - txMax = TFX_MAX; - tyMax = TFY_MAX; - } - else { - txMin = TX_MIN; - tyMin = TY_MIN; - txMax = TX_MAX; - tyMax = TY_MAX; - } - } -} - - -void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - if ( TOUCH_ENABLED() ) { - uint16_t x = 0; - uint16_t y = 0; - uint16_t z1 = 0; - uint16_t z2 = 0; - uint8_t i = 0; - int16_t xraw=0, yraw=0; - - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - - for(; i < 15; i++) { - // SPI requirer 32bit aliment - uint8_t buf[12] = { - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00 - }; - SPI.transfer(&buf[0], &buf[0], 12); - y += (buf[1] << 8 | buf[2])>>3; - x += (buf[4] << 8 | buf[5])>>3; - z1 += (buf[7] << 8 | buf[8])>>3; - z2 += (buf[10] << 8 | buf[11])>>3; - } - enableTouchIrq(); - - if(i == 0) { - *oX = 0; - *oY = 0; - *oZ = 0; - } - else { - x /= i; - y /= i; - z1 /= i; - z2 /= i; - } - - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); - int z = z1 + ADC_MAX - z2; - if (flipped) { - xraw = x; - yraw = y; - } else { - xraw = ADC_MAX - x; - yraw = ADC_MAX - y; - } - xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1); - yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1); - - *oX = xraw; - *oY = yraw; - *oZ = z; - } - else - { - *oX = 0; - *oY = 0; - *oZ = 0; - } -} - -void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - readRaw(oX,oY,oZ); - // callibrate ... - if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin); - if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin); - //Serial.print(*oX); - //Serial.print(" "); - //Serial.println(*oY); -} - - -/*********************************************************************************************** - No DMA functions - ***********************************************************************************************/ -void TFT_T_DMA::fillScreenNoDma(uint16_t color) { - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - int i,j; - for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(arx, ary, arx+arw-1, ary+arh-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - bits = *charpt++; - //digitalWrite(_dc, 1); - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - x +=8; -#ifdef ILI9341 - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); -#endif - digitalWrite(_cs, 1); - SPI.endTransaction(); - } - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - - - -/*********************************************************************************************** - DMA functions - ***********************************************************************************************/ -uint16_t * TFT_T_DMA::getLineBuffer(int j) -{ - uint16_t * block=blocks[j>>6]; - return(&block[(j&0x3F)*TFT_REALWIDTH]); -} - -void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) { - uint8_t *buffer=buf; - uint8_t *src; - - int i,j,y=0; - if (width*2 <= TFT_REALWIDTH) { - for (j=0; j>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH]; - for (i=0; i>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x]; - for (i=0; i>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - block=blocks[l>>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt++; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - x +=8; - } -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { - drawSprite(x,y,bitmap, 0,0,0,0); -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) -{ - int bmp_offx = 0; - int bmp_offy = 0; - uint16_t *bmp_ptr; - - int w =*bitmap++; - int h = *bitmap++; - - - if ( (arw == 0) || (arh == 0) ) { - // no crop window - arx = x; - ary = y; - arw = w; - arh = h; - } - else { - if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - int l=ary; - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx]; - bmp_ptr = (uint16_t*)bitmap; - for (int col=0;col -#include -#include -#endif - -#include "tft_t_dma_config.h" - -#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) -#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define R16(rgb) ((rgb>>8)&0xf8) -#define G16(rgb) ((rgb>>3)&0xfc) -#define B16(rgb) ((rgb<<3)&0xf8) - -#define PAL_COLOR_MASK 0xff - -#ifdef LOHRES -#define TFT_WIDTH 240 -#define TFT_REALWIDTH 240 -#else -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 -#endif -#define TFT_HEIGHT 192 -#define TFT_REALHEIGHT 240 - -//#define WIDTH 272 -//#define HEIGHT 228 - -#define LINES_PER_BLOCK 64 -#define NR_OF_BLOCK 4 -#define SCREEN_DMA_NUM_SETTINGS NR_OF_BLOCK - - -#ifdef ILI9341 - -#define ILI9341_NOP 0x00 -#define ILI9341_SWRESET 0x01 -#define ILI9341_RDDID 0x04 -#define ILI9341_RDDST 0x09 - -#define ILI9341_SLPIN 0x10 -#define ILI9341_SLPOUT 0x11 -#define ILI9341_PTLON 0x12 -#define ILI9341_NORON 0x13 - -#define ILI9341_RDMODE 0x0A -#define ILI9341_RDMADCTL 0x0B -#define ILI9341_RDPIXFMT 0x0C -#define ILI9341_RDIMGFMT 0x0D -#define ILI9341_RDSELFDIAG 0x0F - -#define ILI9341_INVOFF 0x20 -#define ILI9341_INVON 0x21 -#define ILI9341_GAMMASET 0x26 -#define ILI9341_DISPOFF 0x28 -#define ILI9341_DISPON 0x29 - -#define ILI9341_CASET 0x2A -#define ILI9341_PASET 0x2B -#define ILI9341_RAMWR 0x2C -#define ILI9341_RAMRD 0x2E - -#define ILI9341_PTLAR 0x30 -#define ILI9341_MADCTL 0x36 -#define ILI9341_VSCRSADD 0x37 -#define ILI9341_PIXFMT 0x3A - -#define ILI9341_FRMCTR1 0xB1 -#define ILI9341_FRMCTR2 0xB2 -#define ILI9341_FRMCTR3 0xB3 -#define ILI9341_INVCTR 0xB4 -#define ILI9341_DFUNCTR 0xB6 - -#define ILI9341_PWCTR1 0xC0 -#define ILI9341_PWCTR2 0xC1 -#define ILI9341_PWCTR3 0xC2 -#define ILI9341_PWCTR4 0xC3 -#define ILI9341_PWCTR5 0xC4 -#define ILI9341_VMCTR1 0xC5 -#define ILI9341_VMCTR2 0xC7 - -#define ILI9341_RDID1 0xDA -#define ILI9341_RDID2 0xDB -#define ILI9341_RDID3 0xDC -#define ILI9341_RDID4 0xDD - -#define ILI9341_GMCTRP1 0xE0 -#define ILI9341_GMCTRN1 0xE1 - -#define ILI9341_MADCTL_MY 0x80 -#define ILI9341_MADCTL_MX 0x40 -#define ILI9341_MADCTL_MV 0x20 -#define ILI9341_MADCTL_ML 0x10 -#define ILI9341_MADCTL_RGB 0x00 -#define ILI9341_MADCTL_BGR 0x08 -#define ILI9341_MADCTL_MH 0x04 - -#define TFT_CASET ILI9341_CASET -#define TFT_PASET ILI9341_PASET -#define TFT_RAMWR ILI9341_RAMWR -#define TFT_MADCTL ILI9341_MADCTL - -#endif - - -#ifdef ST7789 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_RGB 0x00 -#define ST77XX_MADCTL_BGR 0x08 -#define ST77XX_MADCTL_MH 0x04 - -#define TFT_CASET ST7735_CASET -#define TFT_PASET ST7735_RASET -#define TFT_RAMWR ST7735_RAMWR -#define TFT_MADCTL ST7735_MADCTL - -#endif - - - -#ifdef __cplusplus - -class TFT_T_DMA -{ - public: - TFT_T_DMA(uint8_t _CS, uint8_t _DC, uint8_t _RST = 255, uint8_t _MOSI=11, uint8_t _SCLK=13, uint8_t _MISO=12, uint8_t touch_cs=38, uint8_t touch_irq=37); - - void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); - void begin(void); - void flipscreen(bool flip); - boolean isflipped(void); - void startDMA(void); - void stopDMA(); - int get_frame_buffer_size(int *width, int *height); - - // Touch screen functions - #define TOUCH_ENABLED() ((_touch_cs != 255) && (_touch_irq != 255)) - bool isTouching(void) { return ((!TOUCH_ENABLED())?false:(digitalRead(_touch_irq) == LOW)); } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax); - - // NoDMA functions - void writeScreenNoDma(const uint16_t *pcolors); - void fillScreenNoDma(uint16_t color); - void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - // DMA functions - uint16_t * getLineBuffer(int j); - void writeScreen(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int y, uint16_t *buf); - void fillScreen(uint16_t color); - void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - protected: - uint8_t _rst, _cs, _dc; - uint8_t _miso, _mosi, _sclk; - uint8_t _touch_irq=255, _touch_cs=255; - bool flipped=false; - - void wait(void); - void enableTouchIrq(); -}; - -#endif -#endif diff --git a/MCUME_teensy41/teensyspeccy/tft_t_dma_config.h b/MCUME_teensy41/teensyspeccy/tft_t_dma_config.h deleted file mode 100644 index 0a712da..0000000 --- a/MCUME_teensy41/teensyspeccy/tft_t_dma_config.h +++ /dev/null @@ -1,13 +0,0 @@ -#include "platform_config.h" - -//#define ST7789 1 -//#define ILI9341 1 - -#define TFT_LINEARINT 1 -#define LINEARINT_HACK 1 - -//#define FLIP_SCREEN 1 -//#define TFT_DEBUG 1 -#if defined(__IMXRT1052__) || defined(__IMXRT1062__) -//#define TFT_STATICFB 1 -#endif diff --git a/MCUME_teensy41/teensyspeccy/vga_t_dma.h b/MCUME_teensy41/teensyspeccy/vga_t_dma.h deleted file mode 100644 index 81a986b..0000000 --- a/MCUME_teensy41/teensyspeccy/vga_t_dma.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - Wrapping class to extend VGA_T4 to TFT_T_DMA -*/ - -#ifndef _VGA_T_DMAH_ -#define _VGA_T_DMAH_ - -#ifdef __cplusplus -#include -#endif - - -#define RGBVAL16(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) - - - - -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 - -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - - - -#ifdef __cplusplus - -class TFT_T_DMA: public VGA_T4 -{ - public: - // Fake touch screen functions - bool isTouching(void) { return false; } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { } - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { }; - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { } - - // fake DMA functions - void startDMA(void) { }; - void stopDMA(void) { }; - - // fake no DMA functions - void writeScreenNoDma(const vga_pixel *pcolors) { writeScreen(pcolors); } - void fillScreenNoDma(vga_pixel color) { clear(color); } - void drawTextNoDma(int16_t x, int16_t y, const char * text, vga_pixel fgcolor, vga_pixel bgcolor, bool doublesize) { drawText(x,y,text,fgcolor,bgcolor,doublesize); } - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, vga_pixel color) { drawRect(x, y, w, h, color); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap) { drawSprite(x, y, bitmap); } - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh) { drawSprite(x, y, bitmap, croparx, cropary, croparw, croparh); } -}; - - -#endif -#endif diff --git a/MCUME_teensy41/teensyspeccy/spec.c b/MCUME_teensy41/teensyspeccy/wrapemu.c similarity index 96% rename from MCUME_teensy41/teensyspeccy/spec.c rename to MCUME_teensy41/teensyspeccy/wrapemu.c index 1edbf1c..2739298 100644 --- a/MCUME_teensy41/teensyspeccy/spec.c +++ b/MCUME_teensy41/teensyspeccy/wrapemu.c @@ -303,7 +303,7 @@ void displayscanline(int y, int f_flash) XBuf[col++] = bordercolor; } - emu_DrawLine(XBuf, WIDTH, HEIGHT, y); + emu_DrawLinePal16(XBuf, WIDTH, HEIGHT, y); } static void displayScreen(void) { @@ -467,16 +467,16 @@ void spec_Step(void) { if (iusbhk) hk = iusbhk; kempston_ram = 0x00; - if (k & MASK_JOY2_BTN) + if ( (k & MASK_JOY2_BTN) || (k & MASK_JOY1_BTN) ) kempston_ram |= 0x10; //Fire - if (k & MASK_JOY2_UP) + if ( (k & MASK_JOY2_UP) || (k & MASK_JOY1_UP) ) kempston_ram |= 0x8; //Up - if (k & MASK_JOY2_DOWN) + if ( (k & MASK_JOY2_DOWN) || (k & MASK_JOY1_DOWN) ) kempston_ram |= 0x4; //Down - if (k & MASK_JOY2_RIGHT) - kempston_ram |= 0x2; //Right - if (k & MASK_JOY2_LEFT) - kempston_ram |= 0x1; //Left + if ( (k & MASK_JOY2_RIGHT) || (k & MASK_JOY1_RIGHT) ) + kempston_ram |= 0x1; //Right + if ( (k & MASK_JOY2_LEFT) || (k & MASK_JOY1_LEFT) ) + kempston_ram |= 0x2; //Left UpdateKeyboard(hk); @@ -513,7 +513,7 @@ void buzz(int val, int currentTstates) int sound_size = (currentTstates-lastaudio); if (sound_size < 0) sound_size += CYCLES_PER_FRAME; #if HAS_SND - emu_sndPlayBuzz(sound_size,buzzer_val); +// emu_sndPlayBuzz(sound_size,buzzer_val); #endif //if (val) // buzzer_val = 0; diff --git a/MCUME_teensy41/teensyspeccy/spec.h b/MCUME_teensy41/teensyspeccy/wrapemu.h similarity index 100% rename from MCUME_teensy41/teensyspeccy/spec.h rename to MCUME_teensy41/teensyspeccy/wrapemu.h diff --git a/MCUME_teensy41/teensyuae/autoconf.c b/MCUME_teensy41/teensyuae/autoconf.c index c1558b3..be35c34 100644 --- a/MCUME_teensy41/teensyuae/autoconf.c +++ b/MCUME_teensy41/teensyuae/autoconf.c @@ -260,5 +260,3 @@ void set_uae_int_flag (void) { rtarea[0xFFFB] = uae_int_requested; } - - diff --git a/MCUME_teensy41/teensyuae/autoconf.h b/MCUME_teensy41/teensyuae/autoconf.h index 1f9aa9a..1cf2da2 100644 --- a/MCUME_teensy41/teensyuae/autoconf.h +++ b/MCUME_teensy41/teensyuae/autoconf.h @@ -66,4 +66,3 @@ extern void expansion_init(void); extern uaecptr libemu_InstallFunction(TrapFunction, uaecptr, int, const char *); extern uaecptr libemu_InstallFunctionFlags(TrapFunction, uaecptr, int, int, const char *); - diff --git a/MCUME_teensy41/teensyuae/blitter.c b/MCUME_teensy41/teensyuae/blitter.c index 7518b16..0388c07 100644 --- a/MCUME_teensy41/teensyuae/blitter.c +++ b/MCUME_teensy41/teensyuae/blitter.c @@ -11,7 +11,6 @@ #include "gensound.h" #include "sounddep/sound.h" #include "events.h" -#include "uae.h" #include "memory.h" #include "custom.h" #include "readcpu.h" @@ -462,4 +461,3 @@ void maybe_blit(void) eventtab[ev_blitter].active = 0; regs.spcflags &= ~SPCFLAG_BLTNASTY; } - diff --git a/MCUME_teensy41/teensyuae/dtypes.h b/MCUME_teensy41/teensyuae/dtypes.h index ecca8f5..7fa8de1 100644 --- a/MCUME_teensy41/teensyuae/dtypes.h +++ b/MCUME_teensy41/teensyuae/dtypes.h @@ -29,8 +29,6 @@ typedef ULONG uaecptr; #define REGPARAM2 #endif - -#define SOUND_PRESENT 1 #define M68K_SPEED 8 //#define HAS_BOGOMEM 1 //#define HAS_MEMDISK 1 @@ -39,4 +37,3 @@ typedef ULONG uaecptr; #define HAS_FILESYS 1 #endif /* _DTYPES_H_ */ - diff --git a/MCUME_teensy41/teensyuae/emuapi.cpp b/MCUME_teensy41/teensyuae/emuapi.cpp index c367cb0..e128cca 100644 --- a/MCUME_teensy41/teensyuae/emuapi.cpp +++ b/MCUME_teensy41/teensyuae/emuapi.cpp @@ -5,25 +5,31 @@ extern "C" { #include "iopins.h" } -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#else -#include "tft_t_dma.h" -#endif +#include -#ifdef HAS_USBKEY +#ifdef HAS_USB #include "USBHost_t36.h" // Read this header first for key info USBHost myusb; USBHub hub1(myusb); +#ifdef HAS_USBKEY KeyboardController keyboard1(myusb); USBHIDParser hid1(myusb); MouseController mouse1(myusb); +#endif +#ifdef HAS_USBMIDI MIDIDevice midi1(myusb); #endif +#ifdef HAS_USBJOY +#define COUNT_JOYSTICKS 4 +JoystickController joysticks[COUNT_JOYSTICKS](myusb); +#endif +#endif static bool emu_writeConfig(void); static bool emu_readConfig(void); static bool emu_eraseConfig(void); +static bool emu_writeGfxConfig(char * display_type); +static int emu_readGfxConfig(void); static bool mouseDetected = false; static bool keyboardDetected = false; @@ -34,12 +40,13 @@ static File file; #define MAX_FILES 64 #define AUTORUN_FILENAME "autorun.txt" +#define GFX_CFG_FILENAME "gfxmode.txt" -#define MAX_FILENAME_SIZE 24 +#define MAX_FILENAME_SIZE 34 #define MAX_MENULINES 9 #define TEXT_HEIGHT 16 #define TEXT_WIDTH 8 -#define MENU_FILE_XOFFSET (6*TEXT_WIDTH) +#define MENU_FILE_XOFFSET (2*TEXT_WIDTH) #define MENU_FILE_YOFFSET (2*TEXT_HEIGHT) #define MENU_FILE_W (MAX_FILENAME_SIZE*TEXT_WIDTH) #define MENU_FILE_H (MAX_MENULINES*TEXT_HEIGHT) @@ -53,7 +60,8 @@ static File file; #define MENU_VGA_XOFFSET (MENU_FILE_XOFFSET+MENU_FILE_W+8) #define MENU_VGA_YOFFSET (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37) -extern TFT_T_DMA tft; +#include "t4_dsp.h" +T4_DSP tft; static int nbFiles=0; static int curFile=0; @@ -65,6 +73,8 @@ static char selected_filename[MAX_FILENAME_SIZE]=""; static char second_selected_filename[MAX_FILENAME_SIZE]=""; static bool menuRedraw=true; static bool autorun=false; +static bool vgahires=false; + static const unsigned short * keys; #ifdef TEECOMPUTER @@ -158,6 +168,29 @@ void emu_Free(void * pt) free(pt); } +#define SMEMPOOL (0x800000) +EXTMEM static unsigned char slowmem[SMEMPOOL]; +static int slowmempt = 0; + +void * emu_SMalloc(unsigned int size) +{ + void * mem = (void*)&slowmem[slowmempt]; + slowmempt += size; + + if ( slowmempt > SMEMPOOL ) { + mem = NULL; + emu_printf("failure to allocate slow"); + } + else { + emu_printf("could allocate slow static "); + emu_printf(size); + } + return mem; +} + +void emu_SFree(void * pt) +{ +} /******************************** * Input and keyboard ********************************/ @@ -329,6 +362,12 @@ int emu_ReadKeys(void) #endif if ( row & 0x02 ) retval |= MASK_JOY2_BTN; + +#ifdef EXTPAD + if ( sh_pressed ) retval |= MASK_KEY_USER3; + if ( fn_pressed ) retval |= MASK_KEY_USER1; + digitalWrite(KLED, 0); +#else // Handle LED flash uint32_t time_ms=millis(); if ((time_ms-last_t_ms) > 100) { @@ -412,8 +451,9 @@ int emu_ReadKeys(void) if ( key_fn ) retval |= MASK_KEY_USER2; if ( ( key_fn ) && (keymatrix[4] == 0x10 )) retval |= MASK_KEY_USER1; +#endif - if ( (key_fn) && (key_sh) ) + if ( (fn_pressed) && (sh_pressed) ) #else if ( ((retval & (MASK_KEY_USER1+MASK_KEY_USER2)) == (MASK_KEY_USER1+MASK_KEY_USER2)) || (retval & MASK_KEY_USER4 ) ) @@ -453,8 +493,10 @@ int emu_ReadKeys(void) while (true) { ; } -#endif +#endif } + + emu_GetJoystick(); return (retval); } @@ -607,7 +649,7 @@ int emu_setKeymap(int index) { } int emu_GetMouse(int *x, int *y, int *buts) { -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBKEY) if (mouse1.available()) { *buts = mouse1.getButtons(); *x = mouse1.getMouseX(); @@ -620,7 +662,23 @@ int emu_GetMouse(int *x, int *y, int *buts) { return 0; } -#ifdef HAS_USBKEY +int emu_GetJoystick(void) { +#if defined(HAS_USB) && (HAS_USBJOY) + for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) { + if (joysticks[joystick_index].available()) { + uint64_t axis_mask = joysticks[joystick_index].axisMask(); + uint64_t axis_changed_mask = joysticks[joystick_index].axisChangedMask(); + uint32_t buttons = joysticks[joystick_index].getButtons(); + Serial.printf("Joystick(%d): buttons = %x", joystick_index, buttons); + Serial.println(); + } + } + return 1; +#endif + return 0; +} + +#if defined(HAS_USB) && (HAS_USBKEY) void OnPress(auto key) { keyboardDetected = true; @@ -764,7 +822,7 @@ int emu_KeyboardDetected(void) { return (keyboardDetected?1:0); } -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) static unsigned char midiBuffer[16]; static unsigned char midiLastCmd=0; static int midiDataCnt=0; @@ -772,8 +830,7 @@ static int midiCmdNbParam=0; #endif void emu_MidiOnDataReceived(unsigned char value) { - -#ifdef HAS_USBKEY +#if defined(HAS_USB) && (HAS_USBMIDI) //Serial.println(value, HEX); //10000000 = 128 = note off //10010000 = 144 = note on @@ -941,6 +998,7 @@ void emu_MidiOnDataReceived(unsigned char value) { /******************************** * Menu file loader UI ********************************/ +#ifdef FILEBROWSER static int readNbFiles(void) { int totalFiles = 0; @@ -970,8 +1028,6 @@ static int readNbFiles(void) { return totalFiles; } - - void backgroundMenu(void) { menuRedraw=true; tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00)); @@ -981,11 +1037,13 @@ void backgroundMenu(void) { int handleMenu(uint16_t bClick) { if (autorun) { + toggleMenu(false); + menuRedraw=false; return (ACTION_RUN1); } int action = ACTION_NONE; - if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) ) { + if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) || ( bClick & MASK_KEY_USER2 ) ) { char newpath[MAX_FILENAME_PATH]; strcpy(newpath, selection); strcat(newpath, "/"); @@ -996,17 +1054,31 @@ int handleMenu(uint16_t bClick) File file = SD.open(selection); if (file.isDirectory()) { curFile = 0; - nbFiles = readNbFiles(); + nbFiles = readNbFiles(); + menuRedraw=true; } - else { - action = ACTION_RUN1; + else + { #ifdef TEECOMPUTER - if (key_extmode) { + if ( (key_extmode) || ( key_sh) ) { emu_writeConfig(); } + if ( tft.getMode() < MODE_VGA_320x240) { + if ( bClick & MASK_KEY_USER2 ) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + } + //emu_SwapJoysticks(0); #endif + toggleMenu(false); + menuRedraw=false; + return (ACTION_RUN1); } - menuRedraw=true; } else if ( bClick & MASK_KEY_USER1 ) { menuRedraw=true; @@ -1015,19 +1087,14 @@ int handleMenu(uint16_t bClick) strcat(second_selection, "/"); strcat(second_selection, second_selected_filename); action = ACTION_RUN2; - } - else if ( bClick & MASK_KEY_USER2 ) { - menuRedraw=true; - //action = ACTION_RUN3; - emu_SwapJoysticks(0); - } + } else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) { if (curFile!=0) { menuRedraw=true; curFile--; } } - else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { + else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { if ((curFile-9)>=0) { menuRedraw=true; curFile -= 9; @@ -1042,7 +1109,7 @@ int handleMenu(uint16_t bClick) menuRedraw=true; } } - else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) { + else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) { if ((curFile<(nbFiles-9)) && (nbFiles)) { curFile += 9; menuRedraw=true; @@ -1099,12 +1166,12 @@ int handleMenu(uint16_t bClick) return (action); } -bool menuActive(void) +int menuActive(void) { - return (menuOn); + return (menuOn?1:0); } -void toggleMenu(bool on) { +void toggleMenu(int on) { if (on) { menuOn=true; backgroundMenu(); @@ -1122,7 +1189,7 @@ char * menuSecondSelection(void) { return (second_selection); } - +#endif /******************************** * OSKB handling @@ -1140,8 +1207,9 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) char c[4] = {' ',0,' ',0}; const char * cpt = str; int i=0; - int fb_width,fb_height; - tft.get_frame_buffer_size(&fb_width, &fb_height); + int fb_width,fb_height,fbstride; + + fbstride = tft.get_frame_buffer_size(&fb_width, &fb_height); int ypos = (bottom?(fb_height-2*8):0); int line = row + (bottom?2:0); while ((c[1] = *cpt++)) @@ -1150,7 +1218,7 @@ static void lineOSKB(int xoff, bool bottom, char * str, int row) if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0); else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff); if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff); - tft.drawTextNoDma(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); + tft.drawText(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false); i++; } } @@ -1248,7 +1316,7 @@ int handleOSKB(void) { return retval; } -void toggleOSKB(bool forceon) { +void toggleOSKB(int forceon) { if (forceon) { oskbOn = true; drawOSKB(); @@ -1332,6 +1400,17 @@ int emu_FileRead(void * buf, int size, int handler) #endif } +int emu_FileWrite(void * buf, int size, int handler) +{ +// emu_printf("emu_FileWrite"); +// emu_printi(handler); +#ifdef HCFH + return (file.write(buf, size)); +#else + return (getFileHandler(handler).write(buf, size)); +#endif +} + int emu_FileGetc(int handler) { // emu_printf("FileGetc"); // emu_printi(handler); @@ -1404,6 +1483,9 @@ unsigned int emu_FileSize(const char * filepath) emu_printf(filesize); lofile.close(); } + else { + emu_printf("filesize failed"); + } return(filesize); } @@ -1489,6 +1571,48 @@ static bool emu_eraseConfig(void) SD.remove (ROMSDIR "/" AUTORUN_FILENAME); } +static bool emu_writeGfxConfig(char * display_type) +{ + bool retval = false; + SD.remove ("/" GFX_CFG_FILENAME); + if (strcmp(display_type, "VGA")) { + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_CREAT | O_WRITE))) + { + if (lofile.write(display_type, strlen(display_type)) != strlen(display_type)) { + emu_printf("GFX config write failed"); + } + else { + retval = true; + } + lofile.close(); + } + } + return retval; +} + +#define CFG_VGA 0 +#define CFG_ILI 1 +#define CFG_ST 2 + +static int emu_readGfxConfig(void) +{ + int retval = CFG_VGA; // No file = VGA + if ((lofile = SD.open("/" GFX_CFG_FILENAME, O_READ))) + { + unsigned int filesize = lofile.size(); + if (filesize == 2) // "ST" + { + retval = CFG_ST; + } + else if (filesize == 3) // "ILI" + { + retval = CFG_ILI; + } + lofile.close(); + } + return retval; +} + /******************************** * File IO compatibility ********************************/ @@ -1670,62 +1794,249 @@ FRESULT f_mkdir (const char* path) /******************************** - * Initialization + * GFX wrapper ********************************/ -void emu_init(void) +static unsigned short palette16[PALETTE_SIZE]; +static IntervalTimer myTimer; +volatile boolean vbl=true; +volatile boolean vgatimervsync=false; +static void (*vblCallback)(void) = nullptr; +static int skip=0; + +static void vblCount() { + if (vbl) { + vbl = false; + } else { + vbl = true; + } +} + +void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) +{ + if (index= MODE_VGA_320x240 ) { + if (vgatimervsync) { + while (vbl==vb) {}; + } + else { + tft.waitSync(); + } + } + else { + while (vbl==vb) {}; + } + if (vblCallback != nullptr) { + vblCallback(); + } +} + +void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride) +{ + if (skip == 0) { + tft.writeScreenPal(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); + } +} +void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLinePal(width,height,line, VBuf, palette16); + } +} + +void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine(width,height,line, VBuf); + } +} + +void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line) +{ + if (skip == 0) { + tft.writeLine8(width,height,line, VBuf, palette16); + } +} + +int emu_IsVga(void) +{ + return (tft.getMode() >= MODE_VGA_320x240?1:0); +} + +int emu_IsVgaHires(void) +{ + return (tft.getMode() >= MODE_VGA_640x240?1:0); +} + +int emu_FrameSkip(void) +{ + return skip; +} + + +/******************************** + * AUDIO wrapper +********************************/ +#ifdef HAS_SND + +#include "AudioPlaySystem.h" +AudioPlaySystem mymixer; + +void emu_sndInit() { + Serial.println("sound init"); + mymixer.begin_audio(256, mymixer.snd_Mixer); + mymixer.start(); +} + +void emu_sndPlaySound(int chan, int volume, int freq) +{ + if (chan < 6) { + mymixer.sound(chan, freq, volume); + } + /* + Serial.print(chan); + Serial.print(":" ); + Serial.print(volume); + Serial.print(":" ); + Serial.println(freq); + */ +} + +void emu_sndPlayBuzz(int size, int val) { + mymixer.buzz(size,val); + //Serial.print((val==1)?1:0); + //Serial.print(":"); + //Serial.println(size); +} +#endif + +/******************************** + * Initialization +********************************/ +void emu_init(int hires) { Serial.begin(115200); + vgahires = hires; -#ifdef HAS_USBKEY +#ifdef HAS_USB myusb.begin(); +#ifdef HAS_USBKEY keyboard1.attachPress(OnPress); keyboard1.attachRelease(OnRelease); #endif +#endif - while (!SD.begin(SD_CS)) +#ifdef FILEBROWSER + if (!SD.begin(SD_CS)) { - Serial.println("SD begin failed, retrying..."); - delay(1000); + Serial.println("No SD card detected"); } strcpy(selection,ROMSDIR); - FileHandlersInit(); - nbFiles = readNbFiles(); - - Serial.print("SD initialized, files found: "); Serial.println(nbFiles); +#endif emu_InitJoysticks(); #ifdef SWAP_JOYSTICK - joySwapped = true; + joySwapped = true; #else - joySwapped = false; + joySwapped = false; #endif -#ifdef TEECOMPUTER -#ifndef HAS_T4_VGA - tft.flipscreen(false); -#endif -#endif int keypressed = emu_ReadKeys(); +#ifdef HAS_T4_VGA + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } +#else + int gfx_mode = CFG_VGA; // default +#ifdef FILEBROWSER + gfx_mode = emu_readGfxConfig(); +#endif + // Force VGA if UP pressed + if (keypressed & MASK_JOY2_UP) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("VGA"); +#endif + gfx_mode = CFG_VGA; + } + else { + if (keypressed & MASK_JOY2_LEFT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ST"); +#endif + gfx_mode = CFG_ST; + } + else if (keypressed & MASK_JOY2_RIGHT) + { +#ifdef FILEBROWSER + emu_writeGfxConfig("ILI"); +#endif + gfx_mode = CFG_ILI; + } + } + if (gfx_mode == CFG_VGA) { + if (vgahires) { + tft.begin(MODE_VGA_640x480); + } + else { + tft.begin(MODE_VGA_320x240); + } + } + else + { + tft.begin(gfx_mode == CFG_ILI?MODE_TFTILI_320x240:MODE_TFTST_320x240); + } +#endif + if (keypressed & MASK_JOY2_DOWN) { tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) ); tft.drawTextNoDma(64,48, (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); +#ifdef FILEBROWSER emu_eraseConfig(); delay(1000); +#endif } else { +#ifdef FILEBROWSER if (emu_readConfig()) { autorun = true; } +#endif } +#ifdef FILEBROWSER toggleMenu(true); +#endif } -void emu_start(void) +void emu_start(int vblms, void * callback, int forcetimervsync) { + vgatimervsync = forcetimervsync?true:false; + tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); + tft.startRefresh(); + if (callback != nullptr) { + vblCallback = callback; + } + + myTimer.begin(vblCount, vblms); +#ifdef HAS_SND + emu_sndInit(); +#endif usbnavpad = 0; } diff --git a/MCUME_teensy41/teensyuae/emuapi.h b/MCUME_teensy41/teensyuae/emuapi.h index f77760e..5dd6130 100644 --- a/MCUME_teensy41/teensyuae/emuapi.h +++ b/MCUME_teensy41/teensyuae/emuapi.h @@ -2,127 +2,14 @@ #define EMUAPI_H #include "platform_config.h" - -#define CUSTOM_SND 1 -//#define TIMER_REND 1 - -#define EXTRA_HEAP 0x10 - -// Title: < > -#define TITLE " UAE Emulator " -#define ROMSDIR "/amiga" - -#define emu_Init(ROM1,ROM2) {uae_Start(ROM1,ROM2);} -#define emu_Init2() {uae_Init();} -#define emu_Step(x) {uae_Step();} -#define emu_Input(x) {uae_Input(x);} - -#define MAX_FILENAME_PATH 64 -#define NB_FILE_HANDLER 4 -#define PALETTE_SIZE 1 -#define VID_FRAME_SKIP 0x0 -#define TFT_VBUFFER_YCROP 0 -#define SINGLELINE_RENDERING 1 - -#define R32(rgb) ((rgb>>16)&0xff) -#define G32(rgb) ((rgb>>8)&0xff) -#define B32(rgb) (rgb & 0xff) +#include "emucfg.h" #define ACTION_NONE 0 -#define ACTION_MAXKBDVAL 16 -#define ACTION_EXITKBD 128 -#define ACTION_RUN1 129 -#define ACTION_RUN2 130 -#define ACTION_RUN3 131 - - -#ifdef KEYMAP_PRESENT - -#define keylables_map0_0 (char *)"qwertyuiop\x1a" -#define keylables_map0_1 (char *)" asdfghjkl\x19" -#define keylables_map0_2 (char *)" zxcvbnm,.;/" -#define keylables_map0_3 (char *)" +\x10-" -const unsigned short key_map0[] = { - 'q','w','e','r','t','y','u','i','o','p',127, //lowecase - 0,'a','s','d','f','g','h','j','k','l',10, - 0,'z','x','c','v','b','n','m',',','.',';','/', - 218,216,215,217, //U L R D - 0,'+',' ','-' - }; - -#define keylables_map1_0 (char *)"QWERTYUIOP@" -#define keylables_map1_1 (char *)" ASDFGHJKL\x19" -#define keylables_map1_2 (char *)" ZXCVBNM<>:?" -#define keylables_map1_3 (char *)" =\x10_" -const unsigned short key_map1[] = { - 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase - 0,'A','S','D','F','G','H','J','K','L',10, - 0,'Z','X','C','V','B','N','M','<','>',':','?', - 218,216,215,217, //U L R D - 0,'=',' ','_' - }; - -#define keylables_map2_0 (char *)"!\"#$%^&*()@" -#define keylables_map2_1 (char *)" |\\[]{}' " -#define keylables_map2_2 (char *)" <>:?" -#define keylables_map2_3 (char *)" =\x10_" -const unsigned short key_map2[] = { - '!','"','#','$','%','^','&','*',40,41,'@', // shiftothers - 0, '|','\\',91,0,'{','}','`',0,0,0, - 0, 0,0,0,0,0,0,0,'<','>',':','?', - 218,216,215,217, //U L R D - 0,'=',' ','_' - }; - -#define keylables_map3_0 (char *)"1234567890 " -#define keylables_map3_1 (char *)" " -#define keylables_map3_2 (char *)" " -#define keylables_map3_3 (char *)" " - -const unsigned short key_map3[] = { - '1','2','3','4','5','6','7','8','9','0',0, // digit keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 218,216,215,217, //U L R D - 0,0,' ',0 - }; - -#define keylables_map4_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " -#define keylables_map4_1 (char *)" " -#define keylables_map4_2 (char *)" " -#define keylables_map4_3 (char *)" " - -const unsigned short key_map4[] = { - 194,195,196,197,198,199,200,201,202,203, 0, // function keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 218,216,215,217, //U L R D - 0,0,' ',0 - }; - -#define keylables_map5_0 (char *)" " -#define keylables_map5_1 (char *)" " -#define keylables_map5_2 (char *)" " -#define keylables_map5_3 (char *)" " - -const unsigned short key_map5[] = { - 0,0,0,0,0,0,0,0,0,0,0, // extra keys - 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0,0,0,0,0,0,0,0,0,0,0, - 218,216,215,217, //U L R D - 0,0,' ',0 - }; - -const unsigned short matkeys[] = { - 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 - 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 - 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 - 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN - 0x510,0x010,0x110,0x310, // row 4 - }; - -#endif +#define ACTION_RUN1 1 +#define ACTION_RUN2 2 +#define FORCE_VGATIMERVSYNC 1 +#define SUPPORT_HIRES 1 #define MASK_JOY2_RIGHT 0x0001 #define MASK_JOY2_LEFT 0x0002 @@ -139,23 +26,25 @@ const unsigned short matkeys[] = { #define MASK_JOY1_BTN 0x1000 #define MASK_KEY_USER4 0x2000 - +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) #ifdef __cplusplus extern "C" { +extern void emu_init(int hires=0); +extern void emu_start(int vblms, void * callback, int forcetimervsync=0); #endif - -extern void emu_init(void); -extern void emu_start(void); extern void emu_printf(const char * text); extern void emu_printi(int val); extern void emu_printh(int val); extern void * emu_Malloc(unsigned int size); extern void * emu_MallocI(unsigned int size); extern void emu_Free(void * pt); +extern void * emu_SMalloc(unsigned int size); +extern void emu_SFree(void * pt); extern int emu_FileOpen(const char * filepath, const char * mode); extern int emu_FileRead(void * buf, int size, int handler); +extern int emu_FileWrite(void * buf, int size, int handler); extern int emu_FileGetc(int handler); extern int emu_FileSeek(int handler, int seek, int origin); extern int emu_FileTell(int handler); @@ -166,24 +55,23 @@ extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size); extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek); extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index); -extern void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride); -extern void emu_DrawLine(unsigned char * VBuf, int width, int height, int line); +extern void emu_DrawLinePal16(unsigned char * VBuf, int width, int height, int line); extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line); +extern void emu_DrawScreenPal16(unsigned char * VBuf, int width, int height, int stride); extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line); -extern void emu_CopyLine(int width, int height, int ysrc, int ydst); extern void emu_DrawVsync(void); extern int emu_FrameSkip(void); -extern void * emu_LineBuffer(int line); -extern void emu_tweakVideo(int shiftdelta, int numdelta, int denomdelta); +extern int emu_IsVga(void); +extern int emu_IsVgaHires(void); -extern bool menuActive(void); +extern int menuActive(void); extern char * menuSelection(void); extern char * menuSecondSelection(void); -extern void toggleMenu(bool on); +extern void toggleMenu(int on); extern int handleMenu(unsigned short bClick); extern int handleOSKB(void); -extern void toggleOSKB(bool forceon); +extern void toggleOSKB(int forceon); extern void emu_InitJoysticks(void); extern int emu_SwapJoysticks(int statusOnly); @@ -192,6 +80,7 @@ extern int emu_ReadKeys(void); extern int emu_GetPad(void); extern int emu_GetMouse(int *x, int *y, int *buts); extern int emu_MouseDetected(void); +extern int emu_GetJoystick(void); extern int emu_KeyboardDetected(void); extern int emu_ReadAnalogJoyX(int min, int max); extern int emu_ReadAnalogJoyY(int min, int max); @@ -213,5 +102,4 @@ extern int emu_setKeymap(int index); } #endif - #endif diff --git a/MCUME_teensy41/teensyuae/emucfg.h b/MCUME_teensy41/teensyuae/emucfg.h new file mode 100644 index 0000000..b1d8f1f --- /dev/null +++ b/MCUME_teensy41/teensyuae/emucfg.h @@ -0,0 +1,115 @@ +#ifndef EMUCFG_H +#define EMUCFG_H + +#include "wrapemu.h" + +// Title: < > +#define TITLE " UAE Emulator " +#define ROMSDIR "/amiga" + +#define emu_Init(ROM1,ROM2) {uae_Start(ROM1,ROM2);} +#define emu_Init2() {uae_Init();} +#define emu_Step(x) {uae_Step();} +#define emu_Input(x) {uae_Input(x);} + +#define MAX_FILENAME_PATH 64 +#define NB_FILE_HANDLER 4 + +#define PALETTE_SIZE 1 +#define VID_FRAME_SKIP 0x0 +#define TFT_VBUFFER_YCROP 0 +#define SINGLELINE_RENDERING 1 +#define CUSTOM_SND 1 +//#define TIMER_REND 1 +//#define EXTPAD 1 +#define EXTRA_HEAP 0x10 +#define FILEBROWSER 1 + + +#ifdef KEYMAP_PRESENT + +#define keylables_map0_0 (char *)"qwertyuiop\x1a" +#define keylables_map0_1 (char *)" asdfghjkl\x19" +#define keylables_map0_2 (char *)" zxcvbnm,.;/" +#define keylables_map0_3 (char *)" +\x10-" +const unsigned short key_map0[] = { + 'q','w','e','r','t','y','u','i','o','p',127, //lowecase + 0,'a','s','d','f','g','h','j','k','l',10, + 0,'z','x','c','v','b','n','m',',','.',';','/', + 218,215,216,217, //U L R D + 0,'+',' ','-' + }; + +#define keylables_map1_0 (char *)"1234567890 " +#define keylables_map1_1 (char *)" " +#define keylables_map1_2 (char *)" " +#define keylables_map1_3 (char *)" " +const unsigned short key_map1[] = { + '1','2','3','4','5','6','7','8','9','0',0, // digit keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 218,215,216,217, //U L R D + 0,0,' ',0 + }; + +#define keylables_map2_0 (char *)"!\"#$%^&*()@" +#define keylables_map2_1 (char *)" |\\[]{}' " +#define keylables_map2_2 (char *)" <>:?" +#define keylables_map2_3 (char *)" =\x10_" +const unsigned short key_map2[] = { + '!','"','#','$','%','^','&','*',40,41,'@', // shiftothers + 0, '|','\\','[',']','{','}','`',0,0,0, + 0, 0,0,0,0,0,0,0,'<','>',':','?', + 218,215,216,217, //U L R D + 0,'=',' ','_' + }; + +#define keylables_map3_0 (char *)"QWERTYUIOP@" +#define keylables_map3_1 (char *)" ASDFGHJKL\x19" +#define keylables_map3_2 (char *)" ZXCVBNM<>:?" +#define keylables_map3_3 (char *)" =\x10_" +const unsigned short key_map3[] = { + 'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase + 0,'A','S','D','F','G','H','J','K','L',10, + 0,'Z','X','C','V','B','N','M','<','>',':','?', + 218,215,216,217, //U L R D + 0,'=',' ','_' + }; + +#define keylables_map4_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 " +#define keylables_map4_1 (char *)" " +#define keylables_map4_2 (char *)" " +#define keylables_map4_3 (char *)" " + +const unsigned short key_map4[] = { + 194,195,196,197,198,199,200,201,202,203, 0, // function keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 218,215,216,217, //U L R D + 0,0,' ',0 + }; + +#define keylables_map5_0 (char *)" " +#define keylables_map5_1 (char *)" " +#define keylables_map5_2 (char *)" " +#define keylables_map5_3 (char *)" " + +const unsigned short key_map5[] = { + 0,0,0,0,0,0,0,0,0,0,0, // extra keys + 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0, + 218,216,215,217, //U L R D + 0,0,' ',0 + }; + +const unsigned short matkeys[] = { + 0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1 + 0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2 + 0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3 + 0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN + 0x510,0x010,0x110,0x310, // row 4 + }; + +#endif + +#endif diff --git a/MCUME_teensy41/teensyuae/options.h b/MCUME_teensy41/teensyuae/options.h index 45cccc5..d502f2c 100644 --- a/MCUME_teensy41/teensyuae/options.h +++ b/MCUME_teensy41/teensyuae/options.h @@ -150,7 +150,7 @@ static __inline__ void fuzzy_memset_le32_1 (void *p, uae_u32 c, int offset, int case 2: p2[0] = c; p2[1] = c; break; case 1: p2[0] = c; break; case 0: break; - default: printf("Hit the programmer.\n"); break; + default: /*printf("Hit the programmer.\n");*/ break; } } @@ -195,5 +195,3 @@ extern frame_time_t vsynctime, vsyncmintime; #if defined(AMIGA) && defined(__GNUC__) #include "md-amiga/amiga-kludges.h" #endif - - diff --git a/MCUME_teensy41/teensyuae/platform_config.h b/MCUME_teensy41/teensyuae/platform_config.h index beb49d8..d711193 100644 --- a/MCUME_teensy41/teensyuae/platform_config.h +++ b/MCUME_teensy41/teensyuae/platform_config.h @@ -4,24 +4,23 @@ #define TEECOMPUTER 1 #ifdef TEECOMPUTER - -//#define ILI9341 1 -//#define ST7789 1 -//#define TFTSPI1 1 -#define HAS_T4_VGA 1 -#define HIRES 1 +#define TFTSPI1 1 +//#define HAS_T4_VGA 1 #define HAS_SND 1 +#define HAS_USB 1 +#define HAS_USBMOUSE 1 #define HAS_USBKEY 1 #define PT8211 1 - #else #define HAS_T4_VGA 1 -#define HIRES 1 //#define INVX 1 #define INVY 1 #define HAS_SND 1 +#define HAS_USB 1 +#define HAS_USBMOUSE 1 #define HAS_USBKEY 1 +#define PT8211 1 #endif diff --git a/MCUME_teensy41/teensyuae/t4_dsp.cpp b/MCUME_teensy41/teensyuae/t4_dsp.cpp new file mode 100644 index 0000000..43301fa --- /dev/null +++ b/MCUME_teensy41/teensyuae/t4_dsp.cpp @@ -0,0 +1,1774 @@ +/* + TFT/VGA driver + DMA TFT driver based on C64 ILI9341 dma driver from Frank Bösing, 2017 +*/ + +#include "T4_DSP.h" + +#include +#include + +#include "font8x8.h" + +// TFT constants and variables +#define TFT_LINEARINT 1 +#define LINEARINT_HACK 1 +#define DMA_LINES_PER_BLOCK 64 +#define DMA_NUM_SETTINGS 4 + +#define TFT_SWRESET 0x01 +#define TFT_SLPOUT 0x11 +#define TFT_INVON 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_MADCTL 0x36 +#define TFT_PIXFMT 0x3A +#define TFT_MADCTL_MY 0x80 +#define TFT_MADCTL_MX 0x40 +#define TFT_MADCTL_MV 0x20 +#define TFT_MADCTL_ML 0x10 +#define TFT_MADCTL_RGB 0x00 +#define TFT_MADCTL_BGR 0x08 +#define TFT_MADCTL_MH 0x04 + +#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) +//#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) +//#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) +//#define R16(rgb) ((rgb>>8)&0xf8) +//#define G16(rgb) ((rgb>>3)&0xfc) +//#define B16(rgb) ((rgb<<3)&0xf8) + +// LPSPI4 = SPI0 in Teensy 4.0 +// LPSPI3 = SPI1 in Teensy 4.0 +// LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) + +#ifdef TFTSPI1 +#define SPI SPI1 +#define LPSPIP_TDR LPSPI3_TDR +#define LPSPIP_CR LPSPI3_CR +#define LPSPIP_CFGR1 LPSPI3_CFGR1 +#define LPSPIP_TCR LPSPI3_TCR +#define LPSPIP_DER LPSPI3_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX +#else +#define LPSPIP_TDR LPSPI4_TDR +#define LPSPIP_CR LPSPI4_CR +#define LPSPIP_CFGR1 LPSPI4_CFGR1 +#define LPSPIP_TCR LPSPI4_TCR +#define LPSPIP_DER LPSPI4_DER +#define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX +#endif + +#define SPICLOCK 60000000 +#define SPI_MODE SPI_MODE0 + +// VGA constants and macros +typedef uint8_t vga_pixel; +#define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) + +static DMASetting dmasettings[DMA_NUM_SETTINGS]; +static DMAChannel dmatx; +static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K +static volatile uint8_t rstop = 0; +static volatile bool cancelled = false; +static volatile uint8_t curTransfer = 0; +static uint8_t nbTransfer = 0; +static uint16_t * tft_buffer; +static int tft_width; +static int tft_height; +static int tft_stride; + +#define DELAY_MASK 0x80 +PROGMEM static const uint8_t init_commands[] = { + 1+DELAY_MASK, TFT_SWRESET, 150, + 1+DELAY_MASK, TFT_SLPOUT, 255, + 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, + 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, + 1, TFT_INVON, + 1, TFT_DISPON, + 0 +}; + +// VGA constants and variables +// Objective: +// generates VGA signal fully in hardware with as little as possible CPU help + +// Principle: +// QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) +// 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate +// RGB out, combined to create 8bits(/12bits) output. + +// Note: +// - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels +// - experimental resolution: 352x240,352x480 +// - experimental resolution: 512x240,512x480 (not stable) +// - video memory is allocated using malloc in T4 heap +// - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing +// but tried to be compensated by pixel shifting +// - Default is 8bits RRRGGGBB (332) +// But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! +// - Only ok at 600MHz else some disturbances visible + + + +#define TOP_BORDER 40 +#define PIN_HBLANK 15 + +#define PIN_R_B2 33 +#define PIN_R_B1 4 +#define PIN_R_B0 3 +#define PIN_G_B2 2 +#define PIN_G_B1 13 +#define PIN_G_B0 11 +#define PIN_B_B1 12 +#define PIN_B_B0 10 + + +#define DMA_HACK 0x80 + +#define R16(rgb) ((rgb>>8)&0xf8) +#define G16(rgb) ((rgb>>3)&0xfc) +#define B16(rgb) ((rgb<<3)&0xf8) + +// VGA 640x480@60Hz +// Screen refresh rate 60 Hz +// Vertical refresh 31.46875 kHz +// Pixel freq. 25.175 MHz +// +// Visible area 640 25.422045680238 us +// Front porch 16 0.63555114200596 us +// Sync pulse 96 3.8133068520357 us +// Back porch 48 1.9066534260179 us +// Whole line 800 31.777557100298 us + +#define frame_freq 60.0 // Hz +#define line_freq 31.46875 // KHz +#define pix_freq (line_freq*800) // KHz (25.175 MHz) + +// pix_period = 39.7ns +// H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) +#define frontporch_pix 20 //16 +#define backporch_pix 44 //48 + +// Flexio Clock +// PLL3 SW CLOCK (3) => 480 MHz +// PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) +#define FLEXIO_CLK_SEL_PLL3 3 +#define FLEXIO_CLK_SEL_PLL5 2 + +/* Set video PLL */ +// There are /1, /2, /4, /8, /16 post dividers for the Video PLL. +// The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, +// and CCM_ANALOG_MISC2 register sets according to the following equation. +// PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) + +// nfact: +// This field controls the PLL loop divider. +// Valid range for DIV_SELECT divider value: 27~54. + +#define POST_DIV_SELECT 2 + +// Full buffer including back/front porch +static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; +static uint32_t dstbuffer __attribute__((aligned(32))); + +// Visible vuffer +static vga_pixel * vga_buffer; +static int vga_width; +static int vga_height; +static int vga_stride; + +static int maxpixperline; +static int left_border; +static int right_border; +static int line_double; +static int pix_shift; +static int ref_div_select; +static int ref_freq_num; +static int ref_freq_denom; +static int ref_pix_shift; +static int combine_shiftreg; + +#ifdef DEBUG +static uint32_t ISRTicks_prev = 0; +volatile uint32_t ISRTicks = 0; +#endif + +uint8_t T4_DSP::_rst; +uint8_t T4_DSP::_cs; +uint8_t T4_DSP::_dc; +uint8_t T4_DSP::_mosi; +uint8_t T4_DSP::_sclk; +uint8_t T4_DSP::_vsync_pin = -1; +DMAChannel T4_DSP::flexio1DMA; +DMAChannel T4_DSP::flexio2DMA; + +static volatile uint32_t VSYNC = 0; +static volatile uint32_t currentLine=0; +#define NOP asm volatile("nop\n\t"); +static gfx_mode_t gfxmode = MODE_UNDEFINED; + + +FASTRUN void T4_DSP::TFT_isr(void) { + dmatx.clearInterrupt(); + curTransfer++; + if (curTransfer >= nbTransfer) { + curTransfer = 0; + if (cancelled) { + dmatx.disable(); + rstop = 1; + } + } + arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); +} + +FASTRUN void T4_DSP::QT3_isr(void) { + TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); + TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); + + cli(); + + // V-PULSE + if (currentLine > 0) { + digitalWrite(_vsync_pin, 1); + VSYNC = 0; + } else { + digitalWrite(_vsync_pin, 0); + VSYNC = 1; + } + + currentLine++; + currentLine = currentLine % 525; + + + uint32_t y = (currentLine - TOP_BORDER) >> line_double; + // Visible area + + if (y >= 0 && y < vga_height) { + // Disable DMAs + //DMA_CERQ = flexio2DMA.channel; + //DMA_CERQ = flexio1DMA.channel; + + // Setup source adress + // Aligned 32 bits copy + unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; + flexio2DMA.TCD->SADDR = p; + if (pix_shift & DMA_HACK) + { + // Unaligned copy + uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; + flexio1DMA.TCD->SADDR = p2; + } + else { + p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 + flexio1DMA.TCD->SADDR = p; + } + + // Enable DMAs + //flexio2DMA.enable(); + //flexio1DMA.enable(); + DMA_SERQ = flexio2DMA.channel; + DMA_SERQ = flexio1DMA.channel; + arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); + } + sei(); + +#ifdef DEBUG + ISRTicks++; +#endif + asm volatile("dsb"); +} + +static void setDmaStruct() { + uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; + uint16_t * fb = (uint16_t*)malloc(remaining); + tft_buffer = fb; + tft_width = TFT_WIDTH; + tft_height = TFT_HEIGHT; + tft_stride = TFT_WIDTH; + uint16_t col=RGBVAL16(0x00,0x00,0x00); + int i=0; + while (remaining > 0) { + int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); + blocks[i] = fb; + for (int j=0;jATTR_DST = 1; + dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); + dmasettings[i].interruptAtCompletion(); + fb += len/2; + remaining -= len; + i++; + } + dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); + nbTransfer = i; +} + +static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 +{ +//if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; + CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE + | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 + | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); + CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; + CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL + while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock + const int div_post_pll = 1; // other values: 2,4 + if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; + CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass +} + +T4_DSP::T4_DSP() +{ + _cs = TFT_CS; + _dc = TFT_DC; + _rst = TFT_RST; + _mosi = TFT_MOSI; + _sclk = TFT_SCLK; + pinMode(_dc, OUTPUT); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, 1); + digitalWrite(_dc, 1); + _vsync_pin = 8; +} + + +void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { + int dx=0; + int dy=0; + digitalWrite(_dc, 0); + SPI.transfer(TFT_CASET); + digitalWrite(_dc, 1); + SPI.transfer16(x1+dx); + digitalWrite(_dc, 1); + SPI.transfer16(x2+dx); + digitalWrite(_dc, 0); + SPI.transfer(TFT_PASET); + digitalWrite(_dc, 1); + SPI.transfer16(y1+dy); + digitalWrite(_dc, 1); + SPI.transfer16(y2+dy); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + return; +} + +void T4_DSP::tft_setup(bool isST) { + SPI.setMOSI(_mosi); + SPI.setSCK(_sclk); + SPI.begin(); + // RESET if reset pin defined + if (_rst != 0xff) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + const uint8_t *addr = init_commands; + uint8_t count; + digitalWrite(_cs, 0); + while (count = *addr++) { + uint8_t command = *addr++; + if ( (command == TFT_INVON) && (!isST) ) { + // Skip TFT_INVON for ILI + } + else { + digitalWrite(_dc, 0); // command + SPI.transfer(command); + uint16_t ms = count & DELAY_MASK; + count &= ~DELAY_MASK; + while (--count > 0) { // data + uint8_t data = *addr++; + if ( (command == TFT_MADCTL) && (isST) ) { + data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; + } + digitalWrite(_dc, 1); + SPI.transfer(data); + } + if (ms) { + ms = *addr++; // Read post-command delay time (ms) + if(ms == 255) ms = 500; // If 255, delay for 500 ms + digitalWrite(_cs, 1); + SPI.endTransaction(); + delay(2); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + } + } + } + digitalWrite(_cs, 1); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + SPI.endTransaction(); + /* + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_dc, 0); + digitalWrite(_cs, 0); + SPI.transfer(TFT_MADCTL); + digitalWrite(_dc, 1); + SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); + // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); + digitalWrite(_cs, 1); + SPI.endTransaction(); + */ + cancelled = false; +} + +// display VGA image +gfx_error_t T4_DSP::begin(gfx_mode_t mode) +{ + uint32_t flexio_clock_div; + combine_shiftreg = 0; +// int div_select = 49; +// int num = 135; +// int denom = 100; + int div_select = 20; + int num = 9800; + int denom = 10000; + int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; + int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; + set_videoClock(div_select,num,denom,true); + +#ifdef DEBUG + Serial.println(mode); + Serial.println("mode"); +#endif + + switch(mode) + { + case MODE_TFTILI_320x240: +#ifdef DEBUG + Serial.println("TFTILI_320x240"); +#endif + tft_setup(false); + gfxmode = mode; + break; + case MODE_TFTST_320x240: +#ifdef DEBUG + Serial.println("TFTST_320x240"); +#endif + tft_setup(true); + gfxmode = mode; + break; + + case MODE_VGA_320x240: +#ifdef DEBUG + Serial.println("VGA_320x240"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_320x480: +#ifdef DEBUG + Serial.println("VGA_320x480"); +#endif + left_border = backporch_pix/2; + right_border = frontporch_pix/2; + vga_width = 320; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/2); + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_640x240: +#ifdef DEBUG + Serial.println("VGA_640x240"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/pix_freq; + line_double = 1; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_640x480: +#ifdef DEBUG + Serial.println("VGA_640x480"); +#endif + left_border = backporch_pix; + right_border = frontporch_pix; + vga_width = 640; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = (flexio_freq/pix_freq); + line_double = 0; + pix_shift = 4; + combine_shiftreg = 1; + break; + + case MODE_VGA_512x240: +#ifdef DEBUG + Serial.println("VGA_512x240"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 1; + pix_shift = 0; + break; + + case MODE_VGA_512x480: +#ifdef DEBUG + Serial.println("VGA_512x480"); +#endif + left_border = backporch_pix/1.3; + right_border = frontporch_pix/1.3; + vga_width = 512; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; + line_double = 0; + pix_shift = 0; + break; + + case MODE_VGA_352x240: +#ifdef DEBUG + Serial.println("VGA_352x240"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 240 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 1; + pix_shift = 2+DMA_HACK; + break; + + case MODE_VGA_352x480: +#ifdef DEBUG + Serial.println("VGA_352x480"); +#endif + left_border = backporch_pix/1.75; + right_border = frontporch_pix/1.75; + vga_width = 352; + vga_height = 480 ; + vga_stride = left_border+vga_width+right_border; + flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; + line_double = 0; + pix_shift = 2+DMA_HACK; + break; + } + + if (mode >= MODE_VGA_320x240) + { + if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { + fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); + digitalWrite(_cs, 0); + digitalWrite(_dc, 0); + SPI.transfer(TFT_DISPOFF); + digitalWrite(_cs, 1); + delay(20); + digitalWrite(_cs, 0); + digitalWrite(_cs, 1); + } + gfxmode = mode; + + maxpixperline = vga_stride; + // Save param for tweek adjustment + ref_div_select = div_select; + ref_freq_num = num; + ref_freq_denom = denom; + ref_pix_shift = pix_shift; + +#ifdef DEBUG + Serial.println("frequency"); + Serial.println(flexio_freq); + Serial.println("div"); + Serial.println(flexio_freq/pix_freq); +#endif + + pinMode(_vsync_pin, OUTPUT); + pinMode(PIN_HBLANK, OUTPUT); + + /* Basic pin setup FlexIO1 */ + pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 + pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 + pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 + pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 + /* Basic pin setup FlexIO2 */ + pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 + pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 + pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 + pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 + + /* High speed and drive strength configuration */ + *(portControlRegister(PIN_G_B2)) = 0xFF; + *(portControlRegister(PIN_R_B0)) = 0xFF; + *(portControlRegister(PIN_R_B1)) = 0xFF; + *(portControlRegister(PIN_R_B2)) = 0xFF; + *(portControlRegister(PIN_B_B0)) = 0xFF; + *(portControlRegister(PIN_B_B1)) = 0xFF; + *(portControlRegister(PIN_G_B0)) = 0xFF; + *(portControlRegister(PIN_G_B1)) = 0xFF; + + /* Set clock for FlexIO1 and FlexIO2 */ + CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) + | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); + CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); + CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) + | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); + + + /* Set up pin mux FlexIO1 */ + *(portConfigRegister(PIN_G_B2)) = 0x14; + *(portConfigRegister(PIN_R_B0)) = 0x14; + *(portConfigRegister(PIN_R_B1)) = 0x14; + *(portConfigRegister(PIN_R_B2)) = 0x14; + /* Set up pin mux FlexIO2 */ + *(portConfigRegister(PIN_B_B0)) = 0x14; + *(portConfigRegister(PIN_B_B1)) = 0x14; + *(portConfigRegister(PIN_G_B0)) = 0x14; + *(portConfigRegister(PIN_G_B1)) = 0x14; + + /* Enable the clock */ + CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); + CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); + /* Enable the FlexIO with fast access */ + FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; + + uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; + uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; + + /* Shifter 0 registers for FlexIO2 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 + inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter + stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled + startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable + timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 + timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock + pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output + pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity + shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode + /* Shifter 0 registers for FlexIO1 */ + FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + /* Shifter 0 registers for FlexIO1 */ + parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width + pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 + FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; + + if (combine_shiftreg) { + pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled + FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; + FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; + } + /* Timer 0 registers for FlexIO2 */ + timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset + timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output + timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset + timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare + timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert + stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled + startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled + if (combine_shiftreg) { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag + } + else { + triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag + } + triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low + triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected + pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled + //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 + //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high + timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode + // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) + + int shifts_per_transfer; + if (combine_shiftreg) { + shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 + } + else { + shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 + } + FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); + /* Timer 0 registers for FlexIO1 */ + FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; + FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; + FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); +#ifdef DEBUG + Serial.println("FlexIO setup complete"); +#endif + + /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ + if (combine_shiftreg) { + FLEXIO2_SHIFTSDEN |= (1<<1); + FLEXIO1_SHIFTSDEN |= (1<<1); + } + else { + FLEXIO2_SHIFTSDEN |= (1<<0); + FLEXIO1_SHIFTSDEN |= (1<<0); + } + /* Disable DMA channel so it doesn't start transferring yet */ + flexio1DMA.disable(); + flexio2DMA.disable(); + /* Set up DMA channel to use Shifter 0 trigger */ + flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); + flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); + + + if (combine_shiftreg) { + flexio2DMA.TCD->NBYTES = 8; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 8; + flexio2DMA.TCD->CITER = maxpixperline / 8; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + flexio1DMA.TCD->NBYTES = 8; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 8; + flexio1DMA.TCD->CITER = maxpixperline / 8; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Setup DMA2 Flexio2 copy + flexio2DMA.TCD->NBYTES = 4; + flexio2DMA.TCD->SOFF = 4; + flexio2DMA.TCD->SLAST = -maxpixperline; + flexio2DMA.TCD->BITER = maxpixperline / 4; + flexio2DMA.TCD->CITER = maxpixperline / 4; + flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; + flexio2DMA.TCD->DOFF = 0; + flexio2DMA.TCD->DLASTSGA = 0; + flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + + // Setup DMA1 Flexio1 copy + // Use pixel shift to avoid color smearing? + if (pix_shift & DMA_HACK) + { + if (pix_shift & 0x3 == 0) { + // Aligned 32 bits copy (32bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + else { + // Unaligned (source) 32 bits copy (8bits to 32bits) + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 1; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion + } + } + else + { + // Aligned 32 bits copy + flexio1DMA.TCD->NBYTES = 4; + flexio1DMA.TCD->SOFF = 4; + flexio1DMA.TCD->SLAST = -maxpixperline; + flexio1DMA.TCD->BITER = maxpixperline / 4; + flexio1DMA.TCD->CITER = maxpixperline / 4; + flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; + flexio1DMA.TCD->DOFF = 0; + flexio1DMA.TCD->DLASTSGA = 0; + flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits + flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; + } + } + +#ifdef DEBUG + Serial.println("DMA setup complete"); +#endif + + // enable clocks for QTIMER3: generates the 15KHz for hsync + // Pulse: + // low : 3.8133 us => 569x6.7ns + // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) + // (OLD TEST) + // (4us low, 28us high => 32us) + // (597x6.7ns for 4us) + // (4179x6.7ns for 28us) + CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 + //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 + + #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz + #define MARGIN_D 1000 + + TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer + // Invert output pin as we want the interupt on rising edge + TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) + TMR3_CNTR3 = 0; + TMR3_LOAD3 = 0; + + /* Inverted timings */ + unsigned long long cpu_freq = F_CPU; + unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; + int rate2 = rate; + + int substract = 1; + if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { + substract=5; + rate2=1652; + } + + #ifdef DEBUG + Serial.print("MARGIN_N is: "); + Serial.println(rate2, DEC); + Serial.print("SUBSTRACT is: "); + Serial.println(substract, DEC); +#endif + TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; + TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; + TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; + /* + TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; + TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; + TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; + */ + TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on + TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), + // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) + //configure Teensy pin Compare output + IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 + attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function + NVIC_ENABLE_IRQ(IRQ_QTIMER3); +#ifdef DEBUG + Serial.println("QTIMER3 setup complete"); + Serial.print("V-PIN is "); + Serial.println(_vsync_pin); +#endif + + /* initialize gfx buffer */ + if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift + if (gfxbuffer == NULL) return(GFX_ERROR); +#ifdef DEBUG + Serial.println("Memory allocated"); +#endif + + memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); + vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; +#ifdef DEBUG + Serial.println(vga_stride); + Serial.println(vga_height); + Serial.println("Screen cleared"); +#endif + } + + return(GFX_OK); +} + +gfx_mode_t T4_DSP::getMode(void) +{ + return gfxmode; +} + +void T4_DSP::startRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + curTransfer = 0; + rstop = 0; + //dmatx.begin(true); + dmatx.attachInterrupt(TFT_isr); + setDmaStruct(); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + + digitalWrite(_cs, HIGH); + SPI.begin(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + + LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: + LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX + LPSPIP_TCR = 15; // Framesize 16 Bits + //LPSPIP_FCR = 0; // Fifo Watermark + LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable + LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: + dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); + + dmatx = dmasettings[0]; + digitalWrite(_cs, 0); + setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); + digitalWrite(_dc, 0); + SPI.transfer(TFT_RAMWR); + digitalWrite(_dc, 1); + dmatx.enable(); + } +} + + +void T4_DSP::stopRefresh(void) { + if (gfxmode < MODE_VGA_320x240) { + rstop = 1; + unsigned long m = millis(); + cancelled = true; + while (!rstop) { + if ((millis() - m) > 100) break; + delay(10); + asm volatile("wfi"); + }; + rstop = 0; + delay(50); + cancelled = false; + dmatx.detachInterrupt(); + fillScreen(RGBVAL16(0x00,0x00,0x00)); + SPI.end(); +#ifdef ST7789 +// begin(gfxmode); +#endif + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + } +} + +int T4_DSP::get_frame_buffer_size(int *width, int *height) { + if (gfxmode < MODE_VGA_320x240) { + if (width != nullptr) *width = tft_width; + if (height != nullptr) *height = tft_height; + return tft_stride; + } + else { + if (width != nullptr) *width = vga_width; + if (height != nullptr) *height = vga_height; + return vga_stride; + } +} + +void T4_DSP::waitSync() +{ + if (gfxmode >= MODE_VGA_320x240) { + while (VSYNC == 0) {}; + } +} + +void T4_DSP::waitLine(int line) +{ + if (gfxmode >= MODE_VGA_320x240) { + while (currentLine != line) {}; + } +} + +/*********************************************************************************************** + No DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreenNoDma(uint16_t color) { + if (gfxmode < MODE_VGA_320x240) { + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); + int i,j; + for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(arx, ary, arx+arw-1, ary+arh-1); + bitmap = bitmap + bmp_offy*w + bmp_offx; + for (int row=0;row> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + bits = *charpt++; + //digitalWrite(_dc, 1); + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + bits = bits >> 1; + if (bits&0x01) SPI.transfer16(fgcolor); + else SPI.transfer16(bgcolor); + } + x +=8; + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); + digitalWrite(_cs, 0); + setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); + digitalWrite(_cs, 1); + SPI.endTransaction(); + } + else { + drawText(x, y, text, fgcolor, bgcolor, doublesize); + } +} + + +/*********************************************************************************************** + DMA functions + ***********************************************************************************************/ +void T4_DSP::fillScreen(uint16_t color) { + int i,j; + if (gfxmode < MODE_VGA_320x240) { + for (j=0; j> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + dst=&tft_buffer[l*tft_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor; + else *dst++=bgcolor; + l++; + } + x +=8; + } + } + else { + vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); + vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); + vga_pixel * dst; + while ((c = *text++)) { + const unsigned char * charpt=&font8x8[c][0]; + int l=y; + for (int i=0;i<8;i++) + { + unsigned char bits; + if (doublesize) { + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + dst=&vga_buffer[l*vga_stride+x]; + bits = *charpt++; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + bits = bits >> 1; + if (bits&0x01) *dst++=fgcolor8; + else *dst++=bgcolor8; + l++; + } + x +=8; + } + } +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { + drawSprite(x,y,bitmap, 0,0,0,0); +} + +void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) +{ + int bmp_offx = 0; + int bmp_offy = 0; + uint16_t *bmp_ptr; + int w =*bitmap++; + int h = *bitmap++; + if ( (arw == 0) || (arh == 0) ) { + // no crop window + arx = x; + ary = y; + arw = w; + arh = h; + } + else { + if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { + arw = arw - (x-arx); + arx = arx + (x-arx); + } else { + bmp_offx = arx; + } + if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { + arw -= (arx+arw-x-w); + } + if ( (y > ary) && (y<(ary+arh)) ) { + arh = arh - (y-ary); + ary = ary + (y-ary); + } else { + bmp_offy = ary; + } + if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { + arh -= (ary+arh-y-h); + } + } + int l=ary; + bitmap = bitmap + bmp_offy*w + bmp_offx; + + if (gfxmode < MODE_VGA_320x240) { + for (int row=0;row tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]; + pos +=step; + } + #endif + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i 2) ) y += (tft_height-height)/2; + uint16_t * dst=&tft_buffer[y*tft_stride]; + if (width > tft_width) { +#ifdef TFT_LINEARINT + int delta = (width/(width-tft_width))-1; + int pos = delta; + for (int i=0; i> 8]]; + pos +=step; + } +#endif + } + else if ((width*2) == tft_width) { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]]; + *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i>8)*stride]; + for (i=0; i tft_width) { + int step = ((width << 8)/tft_width); + int pos = 0; + for (int i=0; i> 8]]; + pos +=step; + } + } + else if ((width*2) == tft_width) + { + for (int i=0; i 2) ) y += (vga_height-height)/2; + vga_pixel * dst=&vga_buffer[y*vga_stride]; + if (width > vga_width) { + int step = ((width << 8)/vga_width); + int pos = 0; + for (int i=0; i> 8]; + *dst++ = pix; + pos +=step; + } + } + else if ((width*2) == vga_width) { + for (int i=0; i +#include +#endif + +#include "platform_config.h" +#include "iopins.h" + + + +#ifndef TFT_WIDTH +#define TFT_WIDTH 320 +#endif +#define TFT_REALWIDTH 320 + +#ifndef TFT_HEIGHT +#define TFT_HEIGHT 240 +#endif +#define TFT_REALHEIGHT 240 + + +typedef enum gfx_mode_t +{ + MODE_UNDEFINED = 0, + MODE_TFTILI_320x240 = 1, + MODE_TFTST_320x240 = 2, + MODE_VGA_320x240 = 3, + MODE_VGA_320x480 = 4, + MODE_VGA_352x240 = 5, + MODE_VGA_352x480 = 6, + MODE_VGA_512x240 = 7, + MODE_VGA_512x480 = 8, + MODE_VGA_640x240 = 9, + MODE_VGA_640x480 = 10 +} gfx_mode_t; + +typedef enum gfx_error_t +{ + GFX_OK = 0, + GFX_ERROR = -1 +} gfx_error_t; + + +#ifdef __cplusplus + +class T4_DSP +{ + public: + T4_DSP(); + + gfx_error_t begin(gfx_mode_t mode); + gfx_mode_t getMode(void); + void startRefresh(void); + void stopRefresh(); + + int get_frame_buffer_size(int *width, int *height); + void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); + + // wait next Vsync + void waitSync(); + void waitLine(int line); + + // NoDMA functions + void fillScreenNoDma(uint16_t color); + void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + // DMA functions + void fillScreen(uint16_t color); + void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); + void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); + + void writeLine(int width, int height, int y, uint16_t *buf); + void writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + void writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16); + void writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette16); + + protected: + static uint8_t _rst, _cs, _dc; + static uint8_t _mosi, _sclk; + static uint8_t _vsync_pin; + static DMAChannel flexio1DMA; + static DMAChannel flexio2DMA; + void tft_setup(bool isST); + static void TFT_isr(void); + static void QT3_isr(void); +}; + +#endif +#endif diff --git a/MCUME_teensy41/teensyuae/teensyuae.ino b/MCUME_teensy41/teensyuae/teensyuae.ino index dec16bc..3df3570 100644 --- a/MCUME_teensy41/teensyuae/teensyuae.ino +++ b/MCUME_teensy41/teensyuae/teensyuae.ino @@ -1,134 +1,44 @@ #include "emuapi.h" #include "iopins.h" -#include "uae.h" - - -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -TFT_T_DMA tft; -#else -#include "tft_t_dma.h" -TFT_T_DMA tft = TFT_T_DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, TFT_TOUCH_CS, TFT_TOUCH_INT); -#endif - -bool vgaMode = false; - -static unsigned char palette8[PALETTE_SIZE]; -static unsigned short palette16[PALETTE_SIZE]; -static IntervalTimer myTimer; -volatile boolean vbl=true; -static int skip=0; -static elapsedMicros tius; - - - -static void vblCount() { - if (vbl) { - vbl = false; - } else { - vbl = true; - } -} - -void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) -{ - if (index>8, - 320 & 0xFF, // YEND = 320 - ST7735_INVON , DELAY, // 7: hack - 10, - ST7735_NORON , DELAY, // 8: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 9: Main screen turn on, no args, w/delay - 255 -#endif -}; - -static void dmaInterrupt() { - dmatx.clearInterrupt(); - curTransfer++; - if (curTransfer >= nbTransfer) { - curTransfer = 0; - if (cancelled) { - dmatx.disable(); - rstop = 1; - } - } - arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2); -} - -static void setDmaStruct() { - uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; - int i=0; - uint16_t col=RGBVAL16(0x00,0x00,0x00);; - while (remaining > 0) { - uint16_t * fb = blocks[i]; - int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining); -#ifdef TFT_DEBUG - Serial.println((unsigned long)blocks[i]); - Serial.println(remaining); -#endif - switch (i) { - case 0: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb0[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0x00); -#endif - break; - case 1: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb1[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0xff,0xff); -#endif - break; - case 2: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb2[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0x00,0x00,0xff); -#endif - break; - case 3: - if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0); - //fb=&fb3[0]; -#ifdef TFT_DEBUG - col = RGBVAL16(0xff,0x00,0xff); -#endif - break; - } - blocks[i] = fb; - if (blocks[i] == 0) { - Serial.print("ILI9341 allocaltion failed for block "); - Serial.println(i); - delay(10000); - } - - for (int j=0;jATTR_DST = 1; - dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); - dmasettings[i].interruptAtCompletion(); - remaining -= len; - i++; - } - dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); - nbTransfer = i; -#ifdef TFT_DEBUG - Serial.println(nbTransfer); -#endif -} - - -TFT_T_DMA::TFT_T_DMA(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso, uint8_t touch_cs, uint8_t touch_irq) -{ - _cs = cs; - _dc = dc; - _rst = rst; - _mosi = mosi; - _sclk = sclk; - _miso = miso; - pinMode(_dc, OUTPUT); - pinMode(_cs, OUTPUT); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); - if ( (touch_cs != 255) && (touch_irq != 255) ) { - _touch_irq = touch_irq; - _touch_cs = touch_cs; - pinMode(_touch_cs, OUTPUT); - pinMode(touch_irq, INPUT_PULLUP); - digitalWrite(_touch_cs, 1); - } -} - - -void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { - int dx=0; - int dy=0; -#ifdef ST7789 - if (TFT_REALWIDTH == TFT_REALHEIGHT) - { -#ifdef ROTATE_SCREEN - if (!flipped) { - dy += 80; - } -#else - if (flipped) { - dx += 80; - } -#endif - } -#endif - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - SPI.transfer16(x1+dx); - digitalWrite(_dc, 1); - SPI.transfer16(x2+dx); - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - digitalWrite(_dc, 1); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - return; - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_CASET); - digitalWrite(_dc, 1); - - SPI.transfer16(x1+dx); - SPI.transfer16(x2+dx); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_PASET); - digitalWrite(_dc, 1); - SPI.transfer16(y1+dy); - SPI.transfer16(y2+dy); - - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - -void TFT_T_DMA::begin(void) { - SPI.setMOSI(_mosi); - SPI.setMISO(_miso); - SPI.setSCK(_sclk); - SPI.begin(); - - // Initialize display - if (_rst != 0xff) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - const uint8_t *addr = init_commands; - digitalWrite(_cs, 0); -#ifdef ILI9341 - while (1) { - uint8_t count = *addr++; - if (count-- == 0) break; - - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - - while (count-- > 0) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - } - - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); - SPI.endTransaction(); - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(ILI9341_DISPON); - digitalWrite(_dc, 1); - digitalWrite(_cs, 1); -#endif -#ifdef ST7789 - uint8_t numCommands, numArgs; - uint16_t ms; - numCommands = *addr++; // Number of commands to follow - while(numCommands--) { // For each command... - digitalWrite(_dc, 0); - SPI.transfer(*addr++); - numArgs = *addr++; // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs > 1) { // For each argument... - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - numArgs--; - } - - if (numArgs) { - digitalWrite(_dc, 1); - SPI.transfer(*addr++); - } - if(ms) { - ms = *addr++; // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - digitalWrite(_cs, 1); - SPI.endTransaction(); - delay(ms); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - } - } - digitalWrite(_cs, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - SPI.endTransaction(); - - cancelled = false; - -#ifdef FLIP_SCREEN - flipscreen(true); -#else - flipscreen(false); -#endif -#ifdef ST7789 - if (TFT_REALWIDTH != TFT_REALHEIGHT) - { - flipscreen(true); - } -#endif -}; - - - -void TFT_T_DMA::flipscreen(bool flip) -{ - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_dc, 0); - digitalWrite(_cs, 0); - SPI.transfer(TFT_MADCTL); - digitalWrite(_dc, 1); - if (flip) { - flipped=true; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB); -#endif -#endif - } - else { - flipped=false; -#ifdef ILI9341 - SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); -#endif -#ifdef ST7789 -#ifdef ROTATE_SCREEN - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB); -#else - SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB); -#endif -#endif - } - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - -boolean TFT_T_DMA::isflipped(void) -{ - return(flipped); -} - - -#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) - - -void TFT_T_DMA::startDMA(void) { - curTransfer = 0; - rstop = 0; - //dmatx.begin(true); - dmatx.attachInterrupt(dmaInterrupt); - setDmaStruct(); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - - digitalWrite(_cs, HIGH); - SPI.begin(); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); - - - LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: - LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX - LPSPIP_TCR = 15; // Framesize 16 Bits - //LPSPIP_FCR = 0; // Fifo Watermark - LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable - LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: - dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); - - dmatx = dmasettings[0]; - digitalWrite(_cs, 0); - setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); - digitalWrite(_dc, 0); - SPI.transfer(TFT_RAMWR); - digitalWrite(_dc, 1); - dmatx.enable(); -} - - -void TFT_T_DMA::stopDMA(void) { - rstop = 0; - wait(); - delay(50); - cancelled = false; - dmatx.detachInterrupt(); - fillScreen(RGBVAL16(0x00,0x00,0x00)); - SPI.end(); -#ifdef ST7789 - begin(); -#endif -#ifdef ILI9341 - SPI.begin(); - digitalWrite(_cs, 0); - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - SPI.endTransaction(); - digitalWrite(_cs, 1); - digitalWrite(_dc, 1); -#endif - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); -} - -void TFT_T_DMA::wait(void) { - rstop = 1; - unsigned long m = millis(); - cancelled = true; - while (!rstop) { - if ((millis() - m) > 100) break; - delay(10); - asm volatile("wfi"); - }; - rstop = 0; -} - -int TFT_T_DMA::get_frame_buffer_size(int *width, int *height){ - if (width != nullptr) *width = TFT_REALWIDTH; - if (height != nullptr) *height = TFT_REALHEIGHT; - return TFT_REALWIDTH; -} - - -/*********************************************************************************************** - Touch functions - ***********************************************************************************************/ -/* Code based on ... - * - * @file XPT2046.cpp - * @date 19.02.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the XPT2046 driver for Arduino. - */ - -#define ADC_MAX 0x0fff - -void TFT_T_DMA::enableTouchIrq() -{ - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 }; - SPI.transfer((void*)&buf[0],3); - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); -} - -//Default callibration for non flipped -#define TX_MIN 30 -#define TY_MIN 20 -#define TX_MAX 300 -#define TY_MAX 220 - -//Default callibration for flipped -#define TFX_MIN 20 -#define TFY_MIN 25 -#define TFX_MAX 288 -#define TFY_MAX 221 - -static uint16_t txMin; -static uint16_t tyMin; -static uint16_t txMax; -static uint16_t tyMax; - - -void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { - if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) { - txMin = xMin; - tyMin = yMin; - txMax = xMax; - tyMax = yMax; - } - else { - if (flipped) { - txMin = TFX_MIN; - tyMin = TFY_MIN; - txMax = TFX_MAX; - tyMax = TFY_MAX; - } - else { - txMin = TX_MIN; - tyMin = TY_MIN; - txMax = TX_MAX; - tyMax = TY_MAX; - } - } -} - - -void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - if ( TOUCH_ENABLED() ) { - uint16_t x = 0; - uint16_t y = 0; - uint16_t z1 = 0; - uint16_t z2 = 0; - uint8_t i = 0; - int16_t xraw=0, yraw=0; - - SPI.beginTransaction(SPI_SETTING); - digitalWrite(_touch_cs, LOW); - - for(; i < 15; i++) { - // SPI requirer 32bit aliment - uint8_t buf[12] = { - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00, - (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00 - }; - SPI.transfer(&buf[0], &buf[0], 12); - y += (buf[1] << 8 | buf[2])>>3; - x += (buf[4] << 8 | buf[5])>>3; - z1 += (buf[7] << 8 | buf[8])>>3; - z2 += (buf[10] << 8 | buf[11])>>3; - } - enableTouchIrq(); - - if(i == 0) { - *oX = 0; - *oY = 0; - *oZ = 0; - } - else { - x /= i; - y /= i; - z1 /= i; - z2 /= i; - } - - digitalWrite(_touch_cs, HIGH); - SPI.endTransaction(); - int z = z1 + ADC_MAX - z2; - if (flipped) { - xraw = x; - yraw = y; - } else { - xraw = ADC_MAX - x; - yraw = ADC_MAX - y; - } - xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1); - yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1); - - *oX = xraw; - *oY = yraw; - *oZ = z; - } - else - { - *oX = 0; - *oY = 0; - *oZ = 0; - } -} - -void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { - readRaw(oX,oY,oZ); - // callibrate ... - if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin); - if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin); - //Serial.print(*oX); - //Serial.print(" "); - //Serial.println(*oY); -} - - -/*********************************************************************************************** - No DMA functions - ***********************************************************************************************/ -void TFT_T_DMA::fillScreenNoDma(uint16_t color) { - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - int i,j; - for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(arx, ary, arx+arw-1, ary+arh-1); - //digitalWrite(_dc, 0); - //SPI.transfer(TFT_RAMWR); - - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - bits = *charpt++; - //digitalWrite(_dc, 1); - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - bits = bits >> 1; - if (bits&0x01) SPI.transfer16(fgcolor); - else SPI.transfer16(bgcolor); - } - x +=8; -#ifdef ILI9341 - digitalWrite(_dc, 0); - SPI.transfer(ILI9341_SLPOUT); - digitalWrite(_dc, 1); -#endif - digitalWrite(_cs, 1); - SPI.endTransaction(); - } - - SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); - digitalWrite(_cs, 0); - setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); - digitalWrite(_cs, 1); - SPI.endTransaction(); -} - - - - - - -/*********************************************************************************************** - DMA functions - ***********************************************************************************************/ -uint16_t * TFT_T_DMA::getLineBuffer(int j) -{ - uint16_t * block=blocks[j>>6]; - return(&block[(j&0x3F)*TFT_REALWIDTH]); -} - -void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) { - uint8_t *buffer=buf; - uint8_t *src; - - int i,j,y=0; - if (width*2 <= TFT_REALWIDTH) { - for (j=0; j>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2]; - src=buffer; - for (i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; - if (width > TFT_WIDTH) { -#ifdef TFT_LINEARINT - int delta = (width/(width-TFT_WIDTH))-1; - int pos = delta; - for (int i=0; i> 8]; - pos +=step; - } -#endif - } - else if ((width*2) == TFT_WIDTH) { - for (int i=0; i>6]; - uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH]; - for (i=0; i>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x]; - for (i=0; i>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - block=blocks[l>>6]; - dst=&block[(l&0x3F)*TFT_WIDTH+x]; - bits = *charpt++; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - bits = bits >> 1; - if (bits&0x01) *dst++=fgcolor; - else *dst++=bgcolor; - l++; - } - x +=8; - } -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { - drawSprite(x,y,bitmap, 0,0,0,0); -} - -void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) -{ - int bmp_offx = 0; - int bmp_offy = 0; - uint16_t *bmp_ptr; - - int w =*bitmap++; - int h = *bitmap++; - - - if ( (arw == 0) || (arh == 0) ) { - // no crop window - arx = x; - ary = y; - arw = w; - arh = h; - } - else { - if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { - arw = arw - (x-arx); - arx = arx + (x-arx); - } else { - bmp_offx = arx; - } - if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { - arw -= (arx+arw-x-w); - } - if ( (y > ary) && (y<(ary+arh)) ) { - arh = arh - (y-ary); - ary = ary + (y-ary); - } else { - bmp_offy = ary; - } - if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { - arh -= (ary+arh-y-h); - } - } - - - int l=ary; - bitmap = bitmap + bmp_offy*w + bmp_offx; - for (int row=0;row>6]; - uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx]; - bmp_ptr = (uint16_t*)bitmap; - for (int col=0;col -#include -#include -#endif - -#include "tft_t_dma_config.h" - -#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) -#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define R16(rgb) ((rgb>>8)&0xf8) -#define G16(rgb) ((rgb>>3)&0xfc) -#define B16(rgb) ((rgb<<3)&0xf8) - -#define PAL_COLOR_MASK 0xff - -#ifdef LOHRES -#define TFT_WIDTH 240 -#define TFT_REALWIDTH 240 -#else -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 -#endif -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - -//#define WIDTH 272 -//#define HEIGHT 228 - -#define LINES_PER_BLOCK 64 -#define NR_OF_BLOCK 4 -#define SCREEN_DMA_NUM_SETTINGS NR_OF_BLOCK - - -#ifdef ILI9341 - -#define ILI9341_NOP 0x00 -#define ILI9341_SWRESET 0x01 -#define ILI9341_RDDID 0x04 -#define ILI9341_RDDST 0x09 - -#define ILI9341_SLPIN 0x10 -#define ILI9341_SLPOUT 0x11 -#define ILI9341_PTLON 0x12 -#define ILI9341_NORON 0x13 - -#define ILI9341_RDMODE 0x0A -#define ILI9341_RDMADCTL 0x0B -#define ILI9341_RDPIXFMT 0x0C -#define ILI9341_RDIMGFMT 0x0D -#define ILI9341_RDSELFDIAG 0x0F - -#define ILI9341_INVOFF 0x20 -#define ILI9341_INVON 0x21 -#define ILI9341_GAMMASET 0x26 -#define ILI9341_DISPOFF 0x28 -#define ILI9341_DISPON 0x29 - -#define ILI9341_CASET 0x2A -#define ILI9341_PASET 0x2B -#define ILI9341_RAMWR 0x2C -#define ILI9341_RAMRD 0x2E - -#define ILI9341_PTLAR 0x30 -#define ILI9341_MADCTL 0x36 -#define ILI9341_VSCRSADD 0x37 -#define ILI9341_PIXFMT 0x3A - -#define ILI9341_FRMCTR1 0xB1 -#define ILI9341_FRMCTR2 0xB2 -#define ILI9341_FRMCTR3 0xB3 -#define ILI9341_INVCTR 0xB4 -#define ILI9341_DFUNCTR 0xB6 - -#define ILI9341_PWCTR1 0xC0 -#define ILI9341_PWCTR2 0xC1 -#define ILI9341_PWCTR3 0xC2 -#define ILI9341_PWCTR4 0xC3 -#define ILI9341_PWCTR5 0xC4 -#define ILI9341_VMCTR1 0xC5 -#define ILI9341_VMCTR2 0xC7 - -#define ILI9341_RDID1 0xDA -#define ILI9341_RDID2 0xDB -#define ILI9341_RDID3 0xDC -#define ILI9341_RDID4 0xDD - -#define ILI9341_GMCTRP1 0xE0 -#define ILI9341_GMCTRN1 0xE1 - -#define ILI9341_MADCTL_MY 0x80 -#define ILI9341_MADCTL_MX 0x40 -#define ILI9341_MADCTL_MV 0x20 -#define ILI9341_MADCTL_ML 0x10 -#define ILI9341_MADCTL_RGB 0x00 -#define ILI9341_MADCTL_BGR 0x08 -#define ILI9341_MADCTL_MH 0x04 - -#define TFT_CASET ILI9341_CASET -#define TFT_PASET ILI9341_PASET -#define TFT_RAMWR ILI9341_RAMWR -#define TFT_MADCTL ILI9341_MADCTL - -#endif - - -#ifdef ST7789 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_RGB 0x00 -#define ST77XX_MADCTL_BGR 0x08 -#define ST77XX_MADCTL_MH 0x04 - -#define TFT_CASET ST7735_CASET -#define TFT_PASET ST7735_RASET -#define TFT_RAMWR ST7735_RAMWR -#define TFT_MADCTL ST7735_MADCTL - -#endif - - - -#ifdef __cplusplus - -class TFT_T_DMA -{ - public: - TFT_T_DMA(uint8_t _CS, uint8_t _DC, uint8_t _RST = 255, uint8_t _MOSI=11, uint8_t _SCLK=13, uint8_t _MISO=12, uint8_t touch_cs=38, uint8_t touch_irq=37); - - void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2); - void begin(void); - void flipscreen(bool flip); - boolean isflipped(void); - void startDMA(void); - void stopDMA(); - int get_frame_buffer_size(int *width, int *height); - - // Touch screen functions - #define TOUCH_ENABLED() ((_touch_cs != 255) && (_touch_irq != 255)) - bool isTouching(void) { return ((!TOUCH_ENABLED())?false:(digitalRead(_touch_irq) == LOW)); } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ); - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax); - - // NoDMA functions - void writeScreenNoDma(const uint16_t *pcolors); - void fillScreenNoDma(uint16_t color); - void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - // DMA functions - uint16_t * getLineBuffer(int j); - void writeScreen(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16); - void writeLine(int width, int height, int y, uint16_t *buf); - void fillScreen(uint16_t color); - void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize); - void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap); - void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh); - - protected: - uint8_t _rst, _cs, _dc; - uint8_t _miso, _mosi, _sclk; - uint8_t _touch_irq=255, _touch_cs=255; - bool flipped=false; - - void wait(void); - void enableTouchIrq(); -}; - -#endif -#endif diff --git a/MCUME_teensy41/teensyuae/tft_t_dma_config.h b/MCUME_teensy41/teensyuae/tft_t_dma_config.h deleted file mode 100644 index 354cf74..0000000 --- a/MCUME_teensy41/teensyuae/tft_t_dma_config.h +++ /dev/null @@ -1,14 +0,0 @@ -#include "platform_config.h" - -//#define ST7789 1 -//#define ILI9341 1 - -#define TFT_LINEARINT 1 -#define LINEARINT_HACK 1 - -//#define FLIP_SCREEN 1 -//#define TFT_DEBUG 1 -#if defined(__IMXRT1052__) || defined(__IMXRT1062__) -//#define TFT_STATICFB 1 -#endif - diff --git a/MCUME_teensy41/teensyuae/uae.h b/MCUME_teensy41/teensyuae/uae.h index 3e13c89..8c45a09 100644 --- a/MCUME_teensy41/teensyuae/uae.h +++ b/MCUME_teensy41/teensyuae/uae.h @@ -1,10 +1,3 @@ -extern void uae_Init(void); -extern void uae_Step(void); -extern void uae_Start(char * rom1, char * rom2); -extern void uae_Input(int click); - extern int quit_program; - extern char warning_buffer[256]; - diff --git a/MCUME_teensy41/teensyuae/vga_t_dma.h b/MCUME_teensy41/teensyuae/vga_t_dma.h deleted file mode 100644 index 1b388e8..0000000 --- a/MCUME_teensy41/teensyuae/vga_t_dma.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - Wrapping class to extend VGA_T4 to TFT_T_DMA -*/ - -#ifndef _VGA_T_DMAH_ -#define _VGA_T_DMAH_ - -#ifdef __cplusplus -#include -#endif - - -#define RGBVAL16(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) -#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) - - - -#ifdef HIRES -#define TFT_WIDTH 640 -#define TFT_REALWIDTH 640 -#else -#define TFT_WIDTH 320 -#define TFT_REALWIDTH 320 -#endif - -#define TFT_HEIGHT 240 -#define TFT_REALHEIGHT 240 - - - -#ifdef __cplusplus - -class TFT_T_DMA: public VGA_T4 -{ - public: - // Fake touch screen functions - bool isTouching(void) { return false; } - void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { } - void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { }; - void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { } - - // fake DMA functions - void startDMA(void) { }; - void stopDMA(void) { }; - - // fake no DMA functions - void writeScreenNoDma(const vga_pixel *pcolors) { writeScreen(pcolors); } - void fillScreenNoDma(vga_pixel color) { clear(color); } - void drawTextNoDma(int16_t x, int16_t y, const char * text, vga_pixel fgcolor, vga_pixel bgcolor, bool doublesize) { drawText(x,y,text,fgcolor,bgcolor,doublesize); } - void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, vga_pixel color) { drawRect(x, y, w, h, color); } - void drawSpriteNoDma(int16_t x, int16_t y, const int16_t *bitmap) { drawSprite(x, y, bitmap); } - void drawSpriteNoDma(int16_t x, int16_t y, const int16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh) { drawSprite(x, y, bitmap, croparx, cropary, croparw, croparh); } -}; - - -#endif -#endif - diff --git a/MCUME_teensy41/teensyuae/uae.cpp b/MCUME_teensy41/teensyuae/wrapemu.cpp similarity index 89% rename from MCUME_teensy41/teensyuae/uae.cpp rename to MCUME_teensy41/teensyuae/wrapemu.cpp index eace23f..8c148a3 100644 --- a/MCUME_teensy41/teensyuae/uae.cpp +++ b/MCUME_teensy41/teensyuae/wrapemu.cpp @@ -1,11 +1,8 @@ #include #include "emuapi.h" -#ifdef HAS_T4_VGA -#include "vga_t_dma.h" -#else -#include "tft_t_dma.h" -#endif + +#include "t4_dsp.h" #include "iopins.h" extern "C" { @@ -28,14 +25,7 @@ extern void m68k_reset(void); extern void m68k_go(int); } -#define WIN_W TFT_WIDTH -#ifdef HIRES -#define WIN_H TFT_HEIGHT*2 -#else -#define WIN_H TFT_HEIGHT -#endif - - +static bool hires = true; int version = 100*UAEMAJOR + 10*UAEMINOR + UAEURSAMINOR; struct uae_prefs changed_prefs; struct uae_prefs currprefs = { @@ -57,26 +47,16 @@ struct uae_prefs currprefs = { /* sound_minbsiz */ DEFAULT_SOUND_MINB, /* sound_maxbsiz */ DEFAULT_SOUND_MAXB, -/* gfx_width */ WIN_W, -/* gfx_height */ WIN_H, -#ifdef HAS_T4_VGA -#ifdef HIRES +/* gfx_width */ 0, // filled in init +/* gfx_height */ 0, /* gfx_lores */ 0, -#else -/* gfx_lores */ 1, -#endif -#else -/* gfx_lores */ 1, -#endif + /* gfx_linedbl */ 0, /* gfx_correct_aspect */ 0, -#ifdef HAS_T4_VGA -/* gfx_xcenter */ 40, -/* gfx_ycenter */ 40, -#else -/* gfx_xcenter */ 40, -/* gfx_ycenter */ 40, -#endif + +/* gfx_xcenter */ 0, // filled in init +/* gfx_ycenter */ 0, + /* color_mode */ 0, /* immediate_blits */ 0, @@ -99,11 +79,7 @@ char romfile[MAX_FILENAME] = "./kick13.rom"; char prtname[MAX_FILENAME] = "lpr "; char sername[MAX_FILENAME] = ""; char warning_buffer[256]; -#ifdef HAS_T4_VGA -static char slinebuf[WIN_W]; -#else -static char slinebuf[WIN_W*2]; -#endif +static char slinebuf[TFT_WIDTH*2*2]; //16 bits #define MOUSE_STEP 3 static int prev_hk = 0; @@ -150,8 +126,8 @@ const int16_t keyboardAsciiConv[] = // QWERTY Keyboard /* 0x1F */ INV_KEY, /* 0x20 */ AK_SPC, /* 0x21 */ INV_KEY, // exclamation mark -/* 0x22 */ AK_QUOTE, // double quote -/* 0x23 */ INV_KEY, // diese +/* 0x22 */ INV_KEY, // double quote +/* 0x23 */ AK_QUOTE, // diese /* 0x24 */ INV_KEY, // dollar /* 0x25 */ INV_KEY, // procent /* 0x26 */ AK_NUMBERSIGN, // and @@ -296,9 +272,7 @@ void uae_Input(int bClick) { if (bClick & MASK_KEY_USER2) { if (isMouse) isMouse = false; else isMouse = true; -#ifndef HAS_T4_VGA emu_setKeymap(0); -#endif } // force joystick mode if mouse detected @@ -489,26 +463,22 @@ void write_log (const char *buf) { /*fprintf (stderr, buf); */ } void flush_line(int y) { - if(y >= 0 && y < WIN_H) { -#ifdef HAS_T4_VGA - if (currprefs.gfx_correct_aspect) { - emu_DrawLine8((unsigned char *)slinebuf, WIN_W , WIN_H, y); - } + if(y >= 0 && y < currprefs.gfx_height) { + if (currprefs.gfx_correct_aspect) { + emu_DrawLine16((unsigned short *)slinebuf, currprefs.gfx_width , currprefs.gfx_height, y); + } + else { + if (currprefs.gfx_height > 256) { + int nexty = ((y+1) * currprefs.gfx_height)/256; + y = (y * currprefs.gfx_height)/256; + if (y 256) { - int nexty = ((y+1) * currprefs.gfx_height)/256; - y = (y * currprefs.gfx_height)/256; - if (y