/* SDCARD write protect function */ static uint8_t SDCARD_IsWriteEnabled(void) { #if FATFS_USE_WRITEPROTECT_PIN /* Check if write enabled, pin LOW if write enabled */ return !TM_GPIO_GetInputPinValue(FATFS_WRITEPROTECT_PORT, FATFS_WRITEPROTECT_PIN); #endif /* Card is not write protected */ return 1; }
/* SDCARD detect function */ static uint8_t SDCARD_IsDetected(void) { #if FATFS_USE_DETECT_PIN /* Check if detected, pin LOW if detected */ return !TM_GPIO_GetInputPinValue(FATFS_DETECT_PORT, FATFS_DETECT_PIN); #endif /* Card is detected */ return 1; }
uint8_t TM_FATFS_CheckCardDetectPin(void) { uint8_t status = 1; #if FATFS_USE_DETECT_PIN > 0 if (TM_GPIO_GetInputPinValue(FATFS_USE_DETECT_PIN_PORT, FATFS_USE_DETECT_PIN_PIN) != 0) { status = 0; } #endif /* Return status */ return status; }
uint32_t TM_HCSR04_Read(TM_HCSR04_t* HCSR04) { uint32_t time, timeout; /* Trigger low */ TM_GPIO_SetPinLow(HCSR04->TRIGGER_GPIOx, HCSR04->TRIGGER_GPIO_Pin); /* Delay 2 us */ tm_delay(2); /* Trigger high for 10us */ TM_GPIO_SetPinHigh(HCSR04->TRIGGER_GPIOx, HCSR04->TRIGGER_GPIO_Pin); /* Delay 10 us */ tm_delay(10); /* Trigger low */ TM_GPIO_SetPinLow(HCSR04->TRIGGER_GPIOx, HCSR04->TRIGGER_GPIO_Pin); /* Give some time for response */ timeout = HCSR04_TIMEOUT; while (!TM_GPIO_GetInputPinValue(HCSR04->ECHO_GPIOx, HCSR04->ECHO_GPIO_Pin)) { if (timeout-- == 0x00) { return -1; } } /* Start time */ time = 0; /* Wait till signal is low */ while (TM_GPIO_GetInputPinValue(HCSR04->ECHO_GPIOx, HCSR04->ECHO_GPIO_Pin)) { /* Increase time */ time++; /* Delay 1us */ tm_delay(1); } /* Convert us to cm */ HCSR04->Distance = (float)time * HCSR04_NUMBER; /* Return distance */ return time; }
/* Internal functions */ static void TM_BUTTON_INT_CheckButton(TM_BUTTON_t* ButtonStruct) { uint32_t now, status; /* Read values */ now = TM_DELAY_Time(); status = TM_GPIO_GetInputPinValue(ButtonStruct->GPIOx, ButtonStruct->GPIO_Pin); /* First stage */ if (ButtonStruct->State == BUTTON_STATE_START) { /* Check if pressed */ if (status == ButtonStruct->GPIO_State) { /* Button pressed, go to stage BUTTON_STATE_START */ ButtonStruct->State = BUTTON_STATE_DEBOUNCE; /* Save pressed time */ ButtonStruct->StartTime = now; } } if (ButtonStruct->State == BUTTON_STATE_DEBOUNCE) { /* Button still pressed */ /* Check for debounce */ if (status == ButtonStruct->GPIO_State) { if (now > (ButtonStruct->StartTime + ButtonStruct->PressDebounceTime)) { /* Button debounce OK, Goto Normal Press */ ButtonStruct->State = BUTTON_STATE_PRESSED; /* Try to call user function */ if (ButtonStruct->ButtonHandler) { /* Call function callback */ ButtonStruct->ButtonHandler(ButtonStruct, TM_BUTTON_PressType_OnPressed); } } } else if (status != ButtonStruct->GPIO_State) { /* Not pressed */ /* It was bounce, start over */ /* Go to state BUTTON_STATE_START */ ButtonStruct->State = BUTTON_STATE_START; } } if (ButtonStruct->State == BUTTON_STATE_PRESSED) { /* Button still pressed */ /* Check for long press */ if (status == ButtonStruct->GPIO_State) { if (now > (ButtonStruct->StartTime + ButtonStruct->PressLongTime)) { /* Button pressed OK, call function */ if (ButtonStruct->ButtonHandler) { /* Call function callback */ ButtonStruct->ButtonHandler(ButtonStruct, TM_BUTTON_PressType_Long); } /* Go to stage BUTTON_STATE_WAITRELEASE */ ButtonStruct->State = BUTTON_STATE_WAITRELEASE; } } else if (status != ButtonStruct->GPIO_State) { /* Not pressed */ if (now > (ButtonStruct->StartTime + ButtonStruct->PressNormalTime)) { /* Button pressed OK, call function */ if (ButtonStruct->ButtonHandler) { /* Call function callback */ ButtonStruct->ButtonHandler(ButtonStruct, TM_BUTTON_PressType_Normal); } /* Go to stage BUTTON_STATE_WAITRELEASE */ ButtonStruct->State = BUTTON_STATE_WAITRELEASE; } else { /* Go to state BUTTON_STATE_START */ ButtonStruct->State = BUTTON_STATE_START; } } else { /* Go to state BUTTON_STATE_START */ ButtonStruct->State = BUTTON_STATE_START; } } if (ButtonStruct->State == BUTTON_STATE_WAITRELEASE) { /* Wait till button released */ if (status != ButtonStruct->GPIO_State) { /* Go to stage 0 again */ ButtonStruct->State = BUTTON_STATE_START; } } /* Save current status */ ButtonStruct->LastStatus = status; }
void TM_EXTI_Handler(uint16_t GPIO_Pin) { /* Handle external line 0 interrupts */ if (GPIO_Pin == DTMF_BIT4_PIN) { if(TM_GPIO_GetInputPinValue(DTMF_BIT0_PORT, DTMF_BIT0_PIN)==0){ // Q1 =0 if(TM_GPIO_GetInputPinValue(DTMF_BIT1_PORT, DTMF_BIT1_PIN)==0){// Q2 =0 if(TM_GPIO_GetInputPinValue(DTMF_BIT2_PORT, DTMF_BIT2_PIN)==0){// Q3 =0 if(TM_GPIO_GetInputPinValue(DTMF_BIT3_PORT, DTMF_BIT3_PIN)==0)// Q4 =0 Q321=0 express = 'D'; else express = '8'; } else{ // Q1 =0,Q2=0,Q3=1 if(TM_GPIO_GetInputPinValue(DTMF_BIT3_PORT, DTMF_BIT3_PIN)==0) express = '4'; else express = '#'; } } else //Q1=0,Q2=1, { if(TM_GPIO_GetInputPinValue(DTMF_BIT2_PORT, DTMF_BIT2_PIN)==0){// Q3 =0 if(TM_GPIO_GetInputPinValue(DTMF_BIT3_PORT, DTMF_BIT3_PIN)==0)// Q4 =0 express = '2'; else express = '0'; } else{ // Q1 =0,Q2=1,Q3=1 if(TM_GPIO_GetInputPinValue(DTMF_BIT3_PORT, DTMF_BIT3_PIN)==0) express = '6'; else express = 'B'; } } } else{ //Q1=1 if(TM_GPIO_GetInputPinValue(DTMF_BIT1_PORT, DTMF_BIT1_PIN)==0){// Q2 =0 if(TM_GPIO_GetInputPinValue(DTMF_BIT2_PORT, DTMF_BIT2_PIN)==0){// Q3 =0 if(TM_GPIO_GetInputPinValue(DTMF_BIT3_PORT, DTMF_BIT3_PIN)==0)// Q4 =0 express = '1'; else express = '9'; } else{ // Q1 =1,Q2=0,Q3=1 if(TM_GPIO_GetInputPinValue(DTMF_BIT3_PORT, DTMF_BIT3_PIN)==0) express = '5'; else express = 'A'; } } else //Q1=1,Q2=1, { if(TM_GPIO_GetInputPinValue(DTMF_BIT2_PORT, DTMF_BIT2_PIN)==0){// Q3 =0 if(TM_GPIO_GetInputPinValue(DTMF_BIT3_PORT, DTMF_BIT3_PIN)==0)// Q4 =0 express = '3'; else express = '.'; } else{ // Q1 =1,Q2=1,Q3=1 if(TM_GPIO_GetInputPinValue(DTMF_BIT3_PORT, DTMF_BIT3_PIN)==0) express = '7'; else express = 'C'; } } } TM_USART_Putc(USART3,express); /* Toggle RED led */ // TM_DISCO_LedToggle(LED_RED); // /* Check counter */ if (++counter >= 10) { /* Detach external interrupt for GPIO_Pin_0 no matter on which GPIOx is connected */ TM_EXTI_Detach(GPIO_Pin_0); } } // /* Handle external line 13 interrupts */ if (GPIO_Pin == W1_D0_PIN) { /* run W1 D0 - dieu khien RELAY_DK1_PORT , RELAY_DK1_PIN*/ if(!flag_W1D1) { flag_W1D0 =1 ; flag_W1D1 =0; timeout = value_dip; timer_dk1 =0; } } if (GPIO_Pin == W1_D1_PIN) { /* run W1 D1 - dieu khien RELAY_DK2_PORT , RELAY_DK2_PIN*/ if(!flag_W1D0) { flag_W1D1 =1 ; flag_W1D0 =0 ; timeout = value_dip; timer_dk2 =0; } } if (GPIO_Pin == W2_D1_PIN) { // ngat cac cong /* run w2 D1 */ timerdk1=(timeout*2); timerdk2=(timeout*2); } }
int main(void) { /* complete state of the keyboard split into nibbles according to the FPGA transfer protocol */ unsigned char nibbles[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* map the pins of the DM65PIC to the columns and rows of the C65 and C64 keyboard a very good source of information is chapter 2.1.2 in the following document: http://www.zimmers.net/cbmpics/cbm/c65/c65manual.txt */ struct GPIO_Mapping { GPIO_TypeDef* GPIOx; /* STM32 GPIO port */ uint16_t GPIO_Pin; /* pin within the specified GPIO port */ }; const char Size_ColMapping_C65 = 9; struct GPIO_Mapping Columns_C65[Size_ColMapping_C65] = { GPIOE, GPIO_Pin_9, /* C0 */ GPIOE, GPIO_Pin_10, /* C1 */ GPIOE, GPIO_Pin_11, /* C2 */ GPIOE, GPIO_Pin_12, /* C3 */ GPIOE, GPIO_Pin_13, /* C4 */ GPIOE, GPIO_Pin_14, /* C5 */ GPIOE, GPIO_Pin_15, /* C6 */ GPIOC, GPIO_Pin_0, /* C7 */ GPIOC, GPIO_Pin_1 /* C8 */ }; const char Size_RowMapping_C65 = 11; struct GPIO_Mapping Rows_C65[Size_RowMapping_C65] = { GPIOE, GPIO_Pin_0, /* R0 */ GPIOE, GPIO_Pin_1, /* R1 */ GPIOE, GPIO_Pin_2, /* R2 */ GPIOE, GPIO_Pin_3, /* R3 */ GPIOE, GPIO_Pin_4, /* R4 */ GPIOE, GPIO_Pin_5, /* R5 */ GPIOE, GPIO_Pin_6, /* R6 */ GPIOE, GPIO_Pin_7, /* R7 */ GPIOE, GPIO_Pin_8, /* R8 is exclusively used for the CAPS LOCK aka ASCII/DIN key */ GPIOC, GPIO_Pin_2, /* K1 special "row 9" used for scanning the CURSOR UP key */ GPIOC, GPIO_Pin_3 /* K2 special "row 10" used for scanning the CURSOR LEFT key */ }; struct GPIO_Mapping Restore_C65 = { GPIOC, GPIO_Pin_15 /* RESTORE key */ }; const char Size_ColMapping_C64 = 8; struct GPIO_Mapping Columns_C64[Size_ColMapping_C64] = { GPIOD, GPIO_Pin_8, /* C0 */ GPIOD, GPIO_Pin_9, /* C1 */ GPIOD, GPIO_Pin_10, /* C2 */ GPIOD, GPIO_Pin_11, /* C3 */ GPIOD, GPIO_Pin_12, /* C4 */ GPIOD, GPIO_Pin_13, /* C5 */ GPIOD, GPIO_Pin_14, /* C6 */ GPIOD, GPIO_Pin_15 /* C7 */ }; const char Size_RowMapping_C64 = 8; struct GPIO_Mapping Rows_C64[Size_RowMapping_C64] = { GPIOD, GPIO_Pin_0, /* R0 */ GPIOD, GPIO_Pin_1, /* R1 */ GPIOD, GPIO_Pin_2, /* R2 */ GPIOD, GPIO_Pin_3, /* R3 */ GPIOD, GPIO_Pin_4, /* R4 */ GPIOD, GPIO_Pin_5, /* R5 */ GPIOD, GPIO_Pin_6, /* R6 */ GPIOD, GPIO_Pin_7 /* R7 */ }; struct GPIO_Mapping Restore_C64 = { GPIOC, GPIO_Pin_14 /* RESTORE key */ }; /* joystick mapping at the FPGA's JB port: GPIO => nibble-pos and bit-pos nbl #18 : joystick 1 : bit0=up, bit1=down, bit2=left, bit3=right nbl #19 : bit0=joy1 fire, bit2=capslock key status, bit3=restore key status nbl #20 : joystick 2 : bit0=up, bit1=down, bit2=left, bit3=right nbl #21 : bit0=joy2 fire, bit3=reset momentary-action switch status in C65 mode, which is the default, port #1 and #2 are swapped due to the way, how the DM65PIC is located in the MEGA65 body housing; this is why in below-mentioned table, joystick #1's left is going to nbl #20 instead of #18 */ const char Size_JoyMapping = 10; struct { GPIO_TypeDef* GPIOx; uint16_t GPIO_Pin; char nibble_count; char bit_count; } Joystick[Size_JoyMapping] = { GPIOC, GPIO_Pin_6, 20, 2, /* Joystick #1 LEFT */ GPIOC, GPIO_Pin_7, 20, 3, /* Joystick #1 RIGHT */ GPIOC, GPIO_Pin_4, 20, 0, /* Joystick #1 UP */ GPIOC, GPIO_Pin_5, 20, 1, /* Joystick #1 DOWN */ GPIOC, GPIO_Pin_12, 21, 0, /* Joystick #1 BUTTON */ GPIOC, GPIO_Pin_10, 18, 2, /* Joystick #2 LEFT */ GPIOC, GPIO_Pin_11, 18, 3, /* Joystick #2 RIGHT */ GPIOC, GPIO_Pin_9 , 18, 0, /* Joystick #2 UP */ GPIOC, GPIO_Pin_8, 18, 1, /* Joystick #2 DOWN */ GPIOC, GPIO_Pin_13, 19, 0 /* Joystick #2 BUTTON */ }; struct GPIO_Mapping LEDs[2] = { GPIOB, GPIO_Pin_5, /* Power LED */ GPIOB, GPIO_Pin_4 /* FDD LED */ }; const char ledPower = 0; const char ledFDD = 1; /* positions of special keys within the matrix */ const char COL_CSR = 0; const char ROW_CSR_UP = 9; const char ROW_CSR_LEFT = 10; const char ROW_CAPSLOCK = 8; /* positions of special keys within the nibbles array */ const char NIBBLE_CSR_DOWN = 1; const char BIT_CSR_DOWN = 3; const char NIBBLE_CSR_RIGHT = 0; const char BIT_CSR_RIGHT = 2; const char NIBBLE_RIGHT_SHIFT = 13; const char BIT_RIGHT_SHIFT = 0; const char NIBBLE_RESTORE = 19; const char BIT_RESTORE = 3; const char NIBBLE_CAPSLOCK = 19; const char BIT_CAPSLOCK = 2; int i, col, row, nibble_cnt, bit_cnt; int tmp_offs, tmp_nbl, tmp_bit; char FPGA_IN_PowerLed = 0; char FPGA_IN_FDDLed = 0; /* if ever any key of a C64 keyboard has been pressed, then DM64PIC switches into a dedicated C64 mode that swaps back the joystick ports to their "natural" (aka as printed on the PBC) order because when the DM65PIC is located in a C64 body housing, the ports are placed correctly */ char C64_Mode = 0; /* Initialize System */ SystemInit(); TM_DELAY_Init(); TM_SWO_Init(); TM_SWO_Printf("DM64PIC firmware running.\n"); /* The matrix scan goes like this: let current flow through the columns and then find out if a key is pressed by checking, if the current from the column arrives at a certain row. That means, we configure all rows as outputs (no pullup/pulldown resistor) and all columns as inputs (pulldown resistor) */ for (i = 0; i < Size_ColMapping_C65; i++) TM_GPIO_Init(Columns_C65[i].GPIOx, Columns_C65[i].GPIO_Pin, TM_GPIO_Mode_OUT, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_High); for (i = 0; i < Size_RowMapping_C65; i++) TM_GPIO_Init(Rows_C65[i].GPIOx, Rows_C65[i].GPIO_Pin, TM_GPIO_Mode_IN, TM_GPIO_OType_PP, TM_GPIO_PuPd_DOWN, TM_GPIO_Speed_High); for (i = 0; i < Size_ColMapping_C64; i++) TM_GPIO_Init(Columns_C64[i].GPIOx, Columns_C64[i].GPIO_Pin, TM_GPIO_Mode_OUT, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_High); for (i = 0; i < Size_RowMapping_C64; i++) TM_GPIO_Init(Rows_C64[i].GPIOx, Rows_C64[i].GPIO_Pin, TM_GPIO_Mode_IN, TM_GPIO_OType_PP, TM_GPIO_PuPd_DOWN, TM_GPIO_Speed_High); /* row 8 is exclusively used for CAPS LOCK (aka ASCII/DIN) and has inverse logic (pulled to GND when the key is pressed), so use pullup resistor */ TM_GPIO_Init(Rows_C65[ROW_CAPSLOCK].GPIOx, Rows_C65[ROW_CAPSLOCK].GPIO_Pin, TM_GPIO_Mode_IN, TM_GPIO_OType_PP, TM_GPIO_PuPd_UP, TM_GPIO_Speed_High); /* The RESTORE key is pulled to GND when pressed, so we need a pullup resistor */ TM_GPIO_Init(Restore_C65.GPIOx, Restore_C65.GPIO_Pin, TM_GPIO_Mode_IN, TM_GPIO_OType_PP, TM_GPIO_PuPd_UP, TM_GPIO_Speed_High); TM_GPIO_Init(Restore_C64.GPIOx, Restore_C64.GPIO_Pin, TM_GPIO_Mode_IN, TM_GPIO_OType_PP, TM_GPIO_PuPd_UP, TM_GPIO_Speed_High); /* Joysticks are inverse logic, too, therefore pullup resistors are needed for the inputs */ for (i = 0; i < Size_JoyMapping; i++) TM_GPIO_Init(Joystick[i].GPIOx, Joystick[i].GPIO_Pin, TM_GPIO_Mode_IN, TM_GPIO_OType_PP, TM_GPIO_PuPd_UP, TM_GPIO_Speed_High); /* Initialze outputs for LEDs */ TM_GPIO_Init(LEDs[ledPower].GPIOx, LEDs[ledPower].GPIO_Pin, TM_GPIO_Mode_OUT, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_Low); TM_GPIO_Init(LEDs[ledFDD].GPIOx, LEDs[ledFDD].GPIO_Pin, TM_GPIO_Mode_OUT, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_Low); /* Initialize outputs for communicating with the FPGA via GPIO port JB for debugging JB1 = PG8: clock; data must be valid before rising edge JB2 = PG9: start of sequence, set to 1 when the first nibble of a new 128bit sequence is presented JB3 = PG10: bit0 of output data nibble JB4 = PG11: bit1 of output data nibble JB7 = PG12: bit2 of output data nibble JB8 = PG13: bit3 of output data nibble JB9 = PG14: bit 0 of input bit pair JB10 = PG15: bit 1 of input bit pair */ #define P_CLOCK GPIO_Pin_8 #define P_START GPIO_Pin_9 #define P_OUT_B0 GPIO_Pin_10 #define P_OUT_B1 GPIO_Pin_11 #define P_OUT_B2 GPIO_Pin_12 #define P_OUT_B3 GPIO_Pin_13 #define P_IN_B0 GPIO_Pin_14 #define P_IN_B1 GPIO_Pin_15 /* defines for debug port JA #define P_CLOCK GPIO_Pin_0 #define P_START GPIO_Pin_1 #define P_OUT_B0 GPIO_Pin_2 #define P_OUT_B1 GPIO_Pin_3 #define P_OUT_B2 GPIO_Pin_4 #define P_OUT_B3 GPIO_Pin_5 #define P_IN_B0 GPIO_Pin_6 #define P_IN_B1 GPIO_Pin_7 */ /* initialize the pins for the FPGA GPIO communication */ TM_GPIO_Init(GPIOG, P_CLOCK, TM_GPIO_Mode_OUT, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_High); TM_GPIO_Init(GPIOG, P_START, TM_GPIO_Mode_OUT, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_High); TM_GPIO_Init(GPIOG, P_OUT_B0, TM_GPIO_Mode_OUT, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_High); TM_GPIO_Init(GPIOG, P_OUT_B1, TM_GPIO_Mode_OUT, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_High); TM_GPIO_Init(GPIOG, P_OUT_B2, TM_GPIO_Mode_OUT, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_High); TM_GPIO_Init(GPIOG, P_OUT_B3, TM_GPIO_Mode_OUT, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_High); TM_GPIO_Init(GPIOG, P_IN_B0, TM_GPIO_Mode_IN, TM_GPIO_OType_PP, TM_GPIO_PuPd_DOWN, TM_GPIO_Speed_High); TM_GPIO_Init(GPIOG, P_IN_B1, TM_GPIO_Mode_IN, TM_GPIO_OType_PP, TM_GPIO_PuPd_DOWN, TM_GPIO_Speed_High); /* convenience defines for a better readability */ #define FPGA_OUT(__pin, __value) TM_GPIO_SetPinValue(GPIOG, __pin, __value) #define FPGA_IN(__pin) TM_GPIO_GetInputPinValue(GPIOG, __pin) #define DM_SET_BIT(__nibblepos, __bitpos) nibbles[(__nibblepos)] = nibbles[(__nibblepos)] | (1 << (__bitpos)) #define DM_CLR_BIT(__nibblepos, __bitpos) nibbles[(__nibblepos)] = nibbles[(__nibblepos)] & (~(1 << (__bitpos))) while(1) { /* matrix scan the keyboard */ nibble_cnt = 0; bit_cnt = 0; for (col = 0; col < Size_ColMapping_C65; col++) { /* set all columns to LOW except the currently active one */ for (i = 0; i < Size_ColMapping_C65; i++) { TM_GPIO_SetPinValue(Columns_C65[i].GPIOx, Columns_C65[i].GPIO_Pin, (i == col) ? 1 : 0); if (i < Size_ColMapping_C64) TM_GPIO_SetPinValue(Columns_C64[i].GPIOx, Columns_C64[i].GPIO_Pin, (i == col) ? 1 : 0); } /* perform standard row scanning as the MEGA65 can handle that in an untranslated (raw) way deliberately only scan rows 0..7 as row 8 is only for CAPS LOCK (ASCII/DIN), which needs a special treatment plus: this way of doing it elegantly enables us to scan the C64 rows in parallel */ for (row = 0; row < 8; row++) { /* Commodore 65 */ if (TM_GPIO_GetInputPinValue(Rows_C65[row].GPIOx, Rows_C65[row].GPIO_Pin) == 1) { /* a key is pressed, so set the corresponding matrix bit */ DM_SET_BIT(nibble_cnt, bit_cnt); TM_SWO_Printf("C65 Key: col=%i, row=%i, nibble=%i, bit=%i.\n", col, row, nibble_cnt, bit_cnt); } /* Commodore 64 */ else if (col < Size_ColMapping_C64 ? TM_GPIO_GetInputPinValue(Rows_C64[row].GPIOx, Rows_C64[row].GPIO_Pin) == 1 : 0) { /* detect the C64 mode */ if (!C64_Mode) { C64_Mode = 1; TM_SWO_Printf("C64 mode detected. Swapping joystick ports back to normal.\n"); for (i = 0; i < Size_JoyMapping / 2; i++) { tmp_offs = (Size_JoyMapping / 2) + i; tmp_nbl = Joystick[i].nibble_count; tmp_bit = Joystick[i].bit_count; Joystick[i].nibble_count = Joystick[tmp_offs].nibble_count; Joystick[i].bit_count = Joystick[tmp_offs].bit_count; Joystick[tmp_offs].nibble_count = tmp_nbl; Joystick[tmp_offs].bit_count = tmp_bit; } } /* a key is pressed, so set the corresponding matrix bit */ DM_SET_BIT(nibble_cnt, bit_cnt); TM_SWO_Printf("C64 Key: col=%i, row=%i, nibble=%i, bit=%i.\n", col, row, nibble_cnt, bit_cnt); } /* key is released, so clear the corresponding matrix bit */ else DM_CLR_BIT(nibble_cnt, bit_cnt); bit_cnt++; if (bit_cnt == 4) { bit_cnt = 0; nibble_cnt++; } Delay(1); } } /* C65 only: handle CURSOR UP and CURSOR LEFT: to be emulated as SHIFT+CURSOR DOWN and SHIFT+CURSOR RIGHT */ for (i = 0; i < 8; i++) TM_GPIO_SetPinValue(Columns_C65[i].GPIOx, Columns_C65[i].GPIO_Pin, (i == COL_CSR) ? 1 : 0); if (TM_GPIO_GetInputPinValue(Rows_C65[ROW_CSR_UP].GPIOx, Rows_C65[ROW_CSR_UP].GPIO_Pin) == 1) { /* CURSOR UP */ DM_SET_BIT(NIBBLE_CSR_DOWN, BIT_CSR_DOWN); DM_SET_BIT(NIBBLE_RIGHT_SHIFT, BIT_RIGHT_SHIFT); } Delay(1); if (TM_GPIO_GetInputPinValue(Rows_C65[ROW_CSR_LEFT].GPIOx, Rows_C65[ROW_CSR_LEFT].GPIO_Pin) == 1) { /* CURSOR LEFT */ DM_SET_BIT(NIBBLE_CSR_RIGHT, BIT_CSR_RIGHT); DM_SET_BIT(NIBBLE_RIGHT_SHIFT, BIT_RIGHT_SHIFT); } Delay(1); /* handle RESTORE key (inverse logic) */ if ((TM_GPIO_GetInputPinValue(Restore_C65.GPIOx, Restore_C65.GPIO_Pin) == 0) || (TM_GPIO_GetInputPinValue(Restore_C64.GPIOx, Restore_C64.GPIO_Pin) == 0)) DM_SET_BIT(NIBBLE_RESTORE, BIT_RESTORE); else DM_CLR_BIT(NIBBLE_RESTORE, BIT_RESTORE); Delay(1); /* C65 only: handle CAPS LOCK (aka ASCII/DIN) (inverse logic) */ if (TM_GPIO_GetInputPinValue(Rows_C65[ROW_CAPSLOCK].GPIOx, Rows_C65[ROW_CAPSLOCK].GPIO_Pin) == 0) DM_SET_BIT(NIBBLE_CAPSLOCK, BIT_CAPSLOCK); else DM_CLR_BIT(NIBBLE_CAPSLOCK, BIT_CAPSLOCK); Delay(1); /* handle joysticks */ for (i = 0; i < Size_JoyMapping; i++) { if (TM_GPIO_GetInputPinValue(Joystick[i].GPIOx, Joystick[i].GPIO_Pin) == 0) { DM_SET_BIT(Joystick[i].nibble_count, Joystick[i].bit_count); TM_SWO_Printf("Joystick: i=%i, nibble=%i, bit=%i.\n", i, Joystick[i].nibble_count, Joystick[i].bit_count); } else DM_CLR_BIT(Joystick[i].nibble_count, Joystick[i].bit_count); Delay(1); } /* handle the LEDs */ TM_GPIO_SetPinValue(LEDs[ledPower].GPIOx, LEDs[ledPower].GPIO_Pin, FPGA_IN_PowerLed ? 0 : 1); TM_GPIO_SetPinValue(LEDs[ledFDD].GPIOx, LEDs[ledFDD].GPIO_Pin, FPGA_IN_FDDLed ? 0 : 1); Delay(1); /* transmit current keyboard and joystick state to FPGA and read the LED status from the FPGA */ for (i = 0; i < 32; i++) { FPGA_OUT(P_CLOCK, 0); /* clock = 0 while data is being assembled */ FPGA_OUT(P_START, (i == 0) ? 1 : 0); /* start of sequence = 1 at the very first nibble */ FPGA_OUT(P_OUT_B0, (nibbles[i] & 0x01) ? 0 : 1); /* set data lines and use inverse logic */ FPGA_OUT(P_OUT_B1, (nibbles[i] & 0x02) ? 0 : 1); FPGA_OUT(P_OUT_B2, (nibbles[i] & 0x04) ? 0 : 1); FPGA_OUT(P_OUT_B3, (nibbles[i] & 0x08) ? 0 : 1); Delay(1); /* wait for everything to settle ... */ FPGA_OUT(P_CLOCK, 1); /* ... then clock = 1 to trigger the FPGA to read */ Delay(1); /* give the FPGA's flip/flops some time to read the data */ /* read the LED status */ if (i == 0) { FPGA_IN_PowerLed = FPGA_IN(P_IN_B0); FPGA_IN_FDDLed = FPGA_IN(P_IN_B1); } } } }