__weak void TM_USB_DriveVBUSCallback(TM_USB_t USB_Mode, uint8_t state) { #if defined(USB_USE_FS) && defined(USB_FS_ENABLE_PIN) if (USB_Mode == TM_USB_FS) { if (state == 0) { /* Disable output */ TM_GPIO_SetPinValue(USB_FS_ENABLE_PORT, USB_FS_ENABLE_PIN, !USB_FS_ENABLE_STATE); } else { /* Enable output */ TM_GPIO_SetPinValue(USB_FS_ENABLE_PORT, USB_FS_ENABLE_PIN, USB_FS_ENABLE_STATE); } } #endif #if defined(USB_USE_HS) && defined(USB_HS_ENABLE_PIN) if (USB_Mode == TM_USB_HS) { if (state == 0) { /* Disable output */ TM_GPIO_SetPinValue(USB_HS_ENABLE_PORT, USB_HS_ENABLE_PIN, !USB_HS_ENABLE_STATE); } else { /* Enable output */ TM_GPIO_SetPinValue(USB_HS_ENABLE_PORT, USB_HS_ENABLE_PIN, USB_HS_ENABLE_STATE); } } #endif }
static void TM_HD44780_Cmd4bit(uint8_t cmd) { /* Set output port */ TM_GPIO_SetPinValue(HD44780_D7_PORT, HD44780_D7_PIN, (cmd & 0x08)); TM_GPIO_SetPinValue(HD44780_D6_PORT, HD44780_D6_PIN, (cmd & 0x04)); TM_GPIO_SetPinValue(HD44780_D5_PORT, HD44780_D5_PIN, (cmd & 0x02)); TM_GPIO_SetPinValue(HD44780_D4_PORT, HD44780_D4_PIN, (cmd & 0x01)); HD44780_E_BLINK; }
TM_USB_Result_t TM_USB_InitFS(void) { /* Init DP and DM pins for USB */ TM_GPIO_InitAlternate(GPIOA, GPIO_PIN_9 | GPIO_PIN_11 | GPIO_PIN_12, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_High, GPIO_AF10_OTG_FS); /* Init ID pin */ TM_GPIO_InitAlternate(GPIOA, GPIO_PIN_10, TM_GPIO_OType_OD, TM_GPIO_PuPd_UP, TM_GPIO_Speed_High, GPIO_AF10_OTG_FS); #if defined(USB_FS_USE_ENABLE_PIN) /* Init VBUS ENABLE pin */ TM_GPIO_Init(USB_FS_ENABLE_PORT, USB_FS_ENABLE_PIN, TM_GPIO_Mode_OUT, TM_GPIO_OType_PP, TM_GPIO_PuPd_UP, TM_GPIO_Speed_High); /* Disable USB output */ TM_GPIO_SetPinValue(USB_FS_ENABLE_PORT, USB_FS_ENABLE_PIN, !USB_FS_ENABLE_STATE); #endif /* Enable USB FS Clocks */ __HAL_RCC_USB_OTG_FS_CLK_ENABLE(); /* Set USBFS Interrupt priority */ HAL_NVIC_SetPriority(OTG_FS_IRQn, USB_NVIC_PRIORITY, 0); /* Enable USBFS Interrupt */ HAL_NVIC_EnableIRQ(OTG_FS_IRQn); /* Return OK */ return TM_USB_Result_Ok; }
TM_USB_Result_t TM_USB_InitHS(void) { #if defined(USB_USE_HS) #if defined(USB_USE_ULPI_PHY) /* Use external ULPI PHY */ /* D0 and CLK */ TM_GPIO_InitAlternate(GPIOA, GPIO_PIN_3 | GPIO_PIN_5, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_High, GPIO_AF10_OTG_HS); /* D1 D2 D3 D4 D5 D6 D7 */ TM_GPIO_InitAlternate(GPIOB, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_5 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_High, GPIO_AF10_OTG_HS); /* STP */ TM_GPIO_InitAlternate(GPIOC, GPIO_PIN_0, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_High, GPIO_AF10_OTG_HS); /* NXT */ TM_GPIO_InitAlternate(GPIOH, GPIO_PIN_4, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_High, GPIO_AF10_OTG_HS); /* DIR */ #if defined(USB_USE_STM32F7_DISCOVERY) TM_GPIO_InitAlternate(GPIOC, GPIO_PIN_2, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_High, GPIO_AF10_OTG_HS); #else TM_GPIO_InitAlternate(GPIOI, GPIO_PIN_11, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_High, GPIO_AF10_OTG_HS); #endif /* Enable ULPI clock */ __HAL_RCC_USB_OTG_HS_ULPI_CLK_ENABLE(); #else /* Use embedded PHY */ /* Init ID, VBUS, DP and DM pins for USB */ TM_GPIO_InitAlternate(GPIOB, GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_High, GPIO_AF12_OTG_HS_FS); #if defined(USB_HS_USE_ENABLE_PIN) /* Init VBUS ENABLE pin */ TM_GPIO_Init(USB_HS_ENABLE_PORT, USB_HS_ENABLE_PIN, TM_GPIO_Mode_OUT, TM_GPIO_OType_PP, TM_GPIO_PuPd_UP, TM_GPIO_Speed_High); /* Disable USB output */ TM_GPIO_SetPinValue(USB_HS_ENABLE_PORT, USB_HS_ENABLE_PIN, !USB_HS_ENABLE_STATE); #endif /* USB_HS_USE_ENABLE_PIN */ #endif /* USB_USE_ULPI_PHY */ /* Enable USB HS Clocks */ __HAL_RCC_USB_OTG_HS_CLK_ENABLE(); /* Set USBHS Interrupt priority */ HAL_NVIC_SetPriority(OTG_HS_IRQn, USB_NVIC_PRIORITY, 0); /* Enable USBHS Interrupt */ HAL_NVIC_EnableIRQ(OTG_HS_IRQn); /* Return OK */ return TM_USB_Result_Ok; #else /* Return ERROR */ return TM_USB_Result_Error; #endif }
int main(void) { int accelData[3]; int analogData[BUFFER]; int i=0; for(i=0;i<BUFFER;i++){ analogData[i]=0; } int a = 0; int analogIn = 0; int analogMin, analogMax; /* Initialize system */ SystemInit(); /* Initialize delay */ //TM_DELAY_Init(); /* Initialize PG13 (GREEN LED) and PG14 (RED LED) */ TM_GPIO_Init(GPIOG, GPIO_PIN_13 | GPIO_PIN_14, TM_GPIO_Mode_OUT, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_Fast); TM_GPIO_SetPinValue(GPIOG, GPIO_PIN_14, 1); // Red: ON #ifdef ENABLE_USART /* Initialize USART1 at 115200 baud, TX: PA10, RX: PA9 */ TM_USART_Init(USART1, TM_USART_PinsPack_1, 115200); #endif #ifdef ENABLE_VCP /* Initialize USB Virtual Comm Port */ TM_USB_VCP_Result status = TM_USB_VCP_NOT_CONNECTED; while (TM_USB_VCP_GetStatus() != TM_USB_VCP_CONNECTED) { TM_USB_VCP_Init(); TM_GPIO_TogglePinValue(GPIOG, GPIO_PIN_14); Delay(500000); } SendString("USB VCP initialized and connected\n"); TM_GPIO_TogglePinValue(GPIOG, GPIO_PIN_14 | GPIO_PIN_13); // Red: OFF, Gr: ON #endif #ifdef ENABLE_MMA /* Initialize MMA845X */ uint8_t mma_status = MMA845X_Initialize(MMA_RANGE_4G); if (mma_status == MMA_OK) { SendString("MMA initialized\n"); } else { SendString("MMA initialization failed, error code: "); // Add 48 to the byte value to have character representation, (48 = '0') SendChar('0'+mma_status); SendChar('\n'); } #endif /* Initialize Display */ TM_ILI9341_Init(); TM_ILI9341_Rotate(TM_ILI9341_Orientation_Portrait_1); TM_ILI9341_SetLayer1(); TM_ILI9341_Fill(ILI9341_COLOR_BLACK); /* Fill data on layer 1 */ /* Initialize ADC1 */ TM_ADC_Init(CURRENT_ADC, CURRENT_CH); /* Initialize PE2 and PE3 for digital output (Motor direction) */ TM_GPIO_Init(GPIOE, GPIO_PIN_2 | GPIO_PIN_3, TM_GPIO_Mode_OUT, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_Fast); // Set them to HIGH/LOW TM_GPIO_SetPinHigh(GPIOE, GPIO_PIN_3); TM_GPIO_SetPinLow(GPIOE, GPIO_PIN_2); #ifdef ENABLE_PWM /* Set up PE5 (in front of PE4) for PWM (TIM9 CH1 PP2) (Motor speed control) */ TM_PWM_TIM_t TIM9_Data; // Set PWM to 1kHz frequency on timer TIM4, 1 kHz = 1ms = 1000us TM_PWM_InitTimer(TIM9, &TIM9_Data, 1000); // Initialize PWM on TIM9, Channel 1 and PinsPack 2 = PE5 TM_PWM_InitChannel(&TIM9_Data, TM_PWM_Channel_1, TM_PWM_PinsPack_2); // Set channel 1 value, 50% duty cycle TM_PWM_SetChannelPercent(&TIM9_Data, TM_PWM_Channel_1, 50); #endif /* Initialize DAC channel 2, pin PA5 (Shaker control) */ //TM_DAC_Init(TM_DAC2); /* Set 12bit analog value of 2047/4096 * 3.3V */ //TM_DAC_SetValue(TM_DAC2, 4096); #ifdef ENABLE_DAC // DAC PIN PA5 /* Initialize DAC1, use TIM4 for signal generation */ TM_DAC_SIGNAL_Init(TM_DAC2, TIM4); /* Output predefined triangle signal with frequency of 5kHz */ TM_DAC_SIGNAL_SetSignal(TM_DAC2, TM_DAC_SIGNAL_Signal_Sinus, 50); #endif /* MAIN LOOP */ while (1) { // Read acceleration data #ifdef ENABLE_MMA MMA845X_ReadAcceleration(accelData); #endif // Read analog input analogData[a] = TM_ADC_Read(CURRENT_ADC, CURRENT_CH); a++; if(a==BUFFER) {a=0;} // Analog average analogIn=0; analogMax=0; analogMin=4096; for(i=0;i<BUFFER;i++){ if(analogData[i] > analogMax) { analogMax = analogData[i]; } if(analogData[i] < analogMin) { analogMin = analogData[i]; } analogIn+=analogData[i]; } analogIn/=BUFFER; // Print graphs printGraphsLCD(accelData, analogData[a], analogIn, analogMin, analogMax); // Toggle Green led TM_GPIO_TogglePinValue(GPIOG, GPIO_PIN_13); } }
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); } } } }