/* LU4_main.c 2013-05-09 Started from LU3_main RoJ 2018-06-25 Version 1.2 RoJ * C+Z bug patch 2018-06-25 Version 1.3 RoJ * Updated Flisp Control and trap handling * NOTE: -O2 does NOT work... Use -O1 * * TODO: Move common code to console.h * Replace ST-library */ #include "misc.h" #include "stm32f10x_usart.h" #include "stm32f10x_exti.h" #include "stm32f10x_rcc.h" #include "stm32f10x_gpio.h" #include "console.h" #include "lu4.h" #include "flispcontrol.h" #include "lu_control.h" static volatile unsigned short switch_status_array; static volatile unsigned int debounce_counter; static volatile unsigned char button_pressed; static volatile unsigned char address; static volatile unsigned char autoaddress; static volatile unsigned char modifydata; unsigned char interactive_mode; static volatile unsigned char run_mode; static volatile unsigned char test_mode; extern unsigned char memory[]; /* Chip initialisation */ void initGPIO(void ) { EXTI_InitTypeDef EXTI_InitStructure; /* EXTI structure to init EXT */ NVIC_InitTypeDef NVIC_InitStructure; /* NVIC structure to set up NVIC controller */ GPIO_InitTypeDef GPIO_InitStructure; USART_ClockInitTypeDef USART_ClockInitStructure; USART_InitTypeDef USART_InitStructure; GPIO_AFIODeInit(); GPIO_DeInit(GPIOA); GPIO_DeInit(GPIOB); GPIO_DeInit(GPIOC); USART_DeInit(USART1); RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1, ENABLE ); RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE ); RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE ); RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE); /* PA13 - JTMS */ /* PA14 - JTCK */ /* PA15 - JTDI */ /* PB4 - JTRST */ /* PB3 - JTDO */ /* PA9 - USART TX */ /* PA10 - USART RX */ /* PA11 - USART CTS not used*/ /* PA12 - USART RTS not used */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA, &GPIO_InitStructure); USART_ClockStructInit(&USART_ClockInitStructure); USART_ClockInit(USART1, &USART_ClockInitStructure); USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No ; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_Init(USART1, &USART_InitStructure); USART_Cmd(USART1, ENABLE); //configure NVIC NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //select NVIC channel to configure NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0xF; //set priority to lowest NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0xF; //set subpriority to lowest NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //enable IRQ channel NVIC_Init(&NVIC_InitStructure); //update NVIC registers USART_ITConfig(USART1, USART_IT_TXE, DISABLE); //disable Transmit Data Register empty interrupt USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //enable Receive Data register not empty interrupt /* PB7,6,5,2,1,0 - (One of) External interrupt lines */ /* PB 0 will be interrupt pin */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0); /* Connect EXTI Line to IRQ (port B, pin 0) */ EXTI_InitStructure.EXTI_Line = EXTI_Line0; /* Configure Button EXTI line */ EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; /* select interrupt mode */ EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; /* generate interrupt on falling edge */ EXTI_InitStructure.EXTI_LineCmd = ENABLE; /* enable EXTI line */ EXTI_Init(&EXTI_InitStructure); /* send values to registers */ /* configure NVIC */ NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; /* select NVIC channel to configure */ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F; /* set priority to lowest */ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F; /* set subpriority to lowest */ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; /* enable IRQ channel */ NVIC_Init(&NVIC_InitStructure); /* update NVIC registers */ /* PC0-PC7, 8-bit inport */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; /* */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = ((uint16_t)0xFF); /* eight low bits */ GPIO_Init( GPIOC, &GPIO_InitStructure); /* PC8-PC15, 8 bit outport, Chip select signals */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /* push/pull */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = ((uint16_t) 0xFF00); GPIO_Init( GPIOC, &GPIO_InitStructure); GPIO_PinLockConfig(GPIOC , (uint16_t) 0xFF00 ); /* PB8-PB15, 8-bit outport, (Outbus high ) */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /* push/pull */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = ((uint16_t) 0xFF00); GPIO_Init( GPIOB, &GPIO_InitStructure); /* PA0-PA7, 8-bit outport, (Output low ) */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /* push/pull */ GPIO_InitStructure.GPIO_Pin = ((uint16_t)0xFF); /* eight low bits */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init( GPIOA, &GPIO_InitStructure); consoleInit( ); } /* Low level read and write */ unsigned char readIn( unsigned char i ) { unsigned short d,r; volatile int j; /* Activate chip select in signal */ r = i; r = r << 12; r = r & 0x7000; GPIOC->BSRR = 0x8000; /* Decoder into tristate */ /* Write value to port C (high byte) */ GPIOC->BRR = 0x7F00; /* reset port bits, deactivates all CS */ GPIOC->BSRR = r; /* set bits */ GPIOC->BRR = 0x8000; /* Decoder pull down */ for( j = 0; j < 300; j++); /* Read 16 bit value from port C */ d = GPIO_ReadInputData( GPIOC ); GPIOC->BSRR = 0x8000; /* Decoder into tristate */ GPIOC->BRR = 0x7F00; /* reset port bits, deactivates all CS */ GPIOC->BRR = 0x8000; /* Decoder pull down */ for( j = 0; j < 300; j++); GPIOC->BSRR = 0x8000; /* Decoder into tristate */ /* return low byte */ return (unsigned char) d ; } void outbusHigh( unsigned char c ) { unsigned int r = ( unsigned short ) c ; r = r << 8; /* Write byte to port B (high byte ) */ GPIOB->BRR = ((uint32_t) 0xFF00); /* reset port bits */ GPIOB->BSRR = r; /* set bits */ } void outbusLow( unsigned char c ) { unsigned short r; /* Write byte to port A (low byte ) */ r = c; GPIOA->BRR = ((uint32_t) 0xFF); /* reset port bits */ GPIOA->BSRR = r; /* set bits */ } void selectOut( unsigned char i ) { /* Activate chip select out signal */ unsigned short r = (unsigned short) (i & 0xF); r = r << 8; /* Write value to port C, high word, (low byte) */ GPIOC->BSRR = 0x8000; /* Decoder into tristate */ GPIOC->BRR = ((uint32_t) 0x7F00); /* reset port bits, deactivates all CS */ // GPIOC->BRR = 0x8000; /* Decoder pull down */ // GPIOC->BSRR = 0x8000; /* Decoder into tristate */ GPIOC->BSRR = r; /* set bits */ GPIOC->BRR = 0x8000; /* Decoder pull down */ GPIOC->BSRR = 0x8000; /* Decoder into tristate */ GPIOC->BRR = ((uint32_t) 0x7F00); /* reset port bits */ } /* Refresh/Update routines refresh - copy from hardware to internal data structures update - copy from internal data structures to hardware */ void refreshSwitches(void) { unsigned char c1, c2; c1 = readIn( 1 ); /* LU4 */ c2 = readIn( 2 ); switch_status_array = ((unsigned short) c2 << 8 ); switch_status_array |= (unsigned short) c1; // switch_status_array &= 0x3FFF; } /* Utility routines */ int isDataSetMode( void) { /* return setting for data set mode switch */ refreshSwitches(); return (0x1000 & switch_status_array) ; } int isDataDisplayMode( void) { return ( ! isDataSetMode() ); } int isFlispIrq( void ) { refreshSwitches(); return (IRQ11_FLISP_IRQ & switch_status_array) ; /* Updated by irq */ } int isAddressSetMode( void) { /* return setting for data set mode switch */ refreshSwitches(); return (0x2000 & switch_status_array) ; } int isAddressAutoMode( void) { return ( ! isAddressSetMode() ); } int isRunActive( void ) { refreshSwitches(); return (0x4000 & switch_status_array) ; } void clearDataPath( void ) { unsigned char i,j; /* Clear displays */ outbusHigh (0xFF); outbusLow (0xFF); for( i = 1; i < 9; i++ ) { selectOut( i ); for( j = 0; j < 100; j++ ); } outbusHigh(0); outbusLow (0); selectOut( 6 ); selectOut( 14 ); selectOut( 15 ); } unsigned char tosegcode( unsigned char c ) { switch (c) { case 0: return 0xC0; case 1: return 0xF9; case 2: return 0xA4; case 3: return 0xB0; case 4: return 0x99; case 5: return 0x92; case 6: return 0x82; case 7: return 0xF8; case 8: return 0x80; case 9: return 0x98; case 0xA: return 0x88; case 0xB: return 0x83; case 0xC: return 0xC6; case 0xD: return 0xA1; case 0xE: return 0x86; case 0xF: return 0x8E; default: return 0xFF; } } void setOutDisplay( unsigned char value , unsigned char cs) { outbusLow ( tosegcode( value & 0xF) ); outbusHigh ( tosegcode( (value >> 4)&0xF ) ); selectOut( cs ); } void setDataDisplay( unsigned char value ) { setOutDisplay( value, 7); } void setAddressDisplay( unsigned char value ) { setOutDisplay( value, 8); } static unsigned char mem_adr_toggle = 0; void ackFlipflops( void ) { selectOut( 13 ); /*LU4 */ // selectOut( 0 ); } #define KEY_DEBOUNCE_DELAY 100 static unsigned long time; __attribute__ ((interrupt ("IRQ"))) void SysTick_Handler(void) { /* System 1msec ticks */ if(debounce_counter){ debounce_counter--; ackFlipflops( ); } time ++; } //void f () __attribute__ ((interrupt ("IRQ"))); __attribute__ ((interrupt ("IRQ"))) static void EXTI0_IRQHandler(void) { unsigned short stat; CMD c; /* switch interrupt handler */ if( debounce_counter ) { goto ackirq; } debounce_counter = KEY_DEBOUNCE_DELAY; refreshSwitches(); stat = switch_status_array & 0x8FFF; /* extract IRQ status bits */ c.message = NO_COMMAND; c.p1 = 0; c.p2 = 0; if( stat & IRQ0_DATA_HIGH_INCREMENT) { if (!(DATA_SET_MODE & switch_status_array)) goto ackirq; c.message = MEM_DATA_H_INC; mem_adr_toggle ^= 0x80; if( (mem_adr_toggle & 0x80 )==0) goto ackirq; }else if( stat & IRQ1_DATA_HIGH_DECREMENT) { if (!(DATA_SET_MODE & switch_status_array)) goto ackirq; c.message = MEM_DATA_H_DEC; mem_adr_toggle ^= 0x40; if( (mem_adr_toggle & 0x40 )==0) goto ackirq; }else if( stat & IRQ2_DATA_LOW_INCREMENT) { if (!(DATA_SET_MODE & switch_status_array)) goto ackirq; c.message = MEM_DATA_L_INC; mem_adr_toggle ^= 0x20; if( (mem_adr_toggle & 0x20 )==0) goto ackirq; }else if( stat & IRQ3_DATA_LOW_DECREMENT) { if (!(DATA_SET_MODE & switch_status_array)) goto ackirq; c.message = MEM_DATA_L_DEC; mem_adr_toggle ^= 0x10; if( (mem_adr_toggle & 0x10 )==0) goto ackirq; }else if( stat & IRQ4_ADDRESS_HIGH_INCREMENT) { if( isAddressAutoMode()) goto ackirq; c.message = MEM_ADDR_H_INC; mem_adr_toggle ^= 8; if( (mem_adr_toggle & 8 )== 0) goto ackirq; }else if( stat & IRQ5_ADDRESS_HIGH_DECREMENT) { if( isAddressAutoMode()) goto ackirq; c.message = MEM_ADDR_H_DEC; mem_adr_toggle ^= 4; if( (mem_adr_toggle & 4 )== 0) goto ackirq; }else if( stat & IRQ6_ADDRESS_LOW_INCREMENT) { if( isAddressAutoMode()) goto ackirq; c.message = MEM_ADDR_L_INC; mem_adr_toggle ^= 2; if( (mem_adr_toggle & 2 )== 0) goto ackirq; }else if( stat & IRQ7_ADDRESS_LOW_DECREMENT) { if( isAddressAutoMode()) goto ackirq; c.message = MEM_ADDR_L_DEC; mem_adr_toggle ^= 1; if( (mem_adr_toggle & 1 )== 0) goto ackirq; }else if( stat & IRQ8_DATA_SET) { c.message = MEM_DATA_SET; }else if( stat & IRQ9_FLISP_RESET) { c.message = FLISP_RESET; }else if( stat & IRQ10_FLISP_STEP) { c.message = STEP_INSTRUCTION; // }else if( stat & IRQ11_FLISP_IRQ) // { c.message = FLISP_NF; }else { /* spurious interrupt */ } putCmd( &c ); ackirq: ackFlipflops( ); /* Ack controller */ EXTI_ClearITPendingBit(EXTI_Line0); } void updateDataDisplay( unsigned char cmd ) { if( isDataDisplayMode() ) { /* just update the display */ if( isAddressAutoMode() ) setDataDisplay( getMemory( autoaddress, 0 ) /*memory[autoaddress]*/ ); else setDataDisplay( getMemory( address, 0 ) /*memory[address]*/ ); }else{ /* Data modify mode */ switch( cmd ) { case MEM_DATA_H_INC: modifydata += 0x10; break; case MEM_DATA_H_DEC: modifydata -= 0x10; break; case MEM_DATA_L_INC: modifydata = (modifydata & 0xF0 ) + ((modifydata + 1) & 0xF); break; case MEM_DATA_L_DEC: modifydata = (modifydata & 0xF0 ) + ((modifydata - 1) & 0xF); break; } setDataDisplay( modifydata ); } } void updateAddressDisplay( unsigned char cmd ) { if( isAddressAutoMode() ) { /* just update the display with memory address register */ setAddressDisplay( autoaddress ); }else{ /* Address modify mode */ switch( cmd ) { case MEM_ADDR_H_INC: address = address + 0x10; break; case MEM_ADDR_H_DEC: address = address - 0x10; break; case MEM_ADDR_L_INC: address = (address & 0xF0 ) + ((address + 1) & 0xF); break; case MEM_ADDR_L_DEC: address = (address & 0xF0 ) + ((address - 1) & 0xF); break; } setAddressDisplay( address ); } } void setAutoAddress(unsigned char add) { autoaddress = add; } int toggleTestMode(void) { if( test_mode ) { test_mode = 0; return 1; } return 0; } void doTestMode( void ) { int i,j; for( i = 0; i <= 0xF ; i++ ) { if( !test_mode ) return; setAddressDisplay( (unsigned char) i ); setDataDisplay( (unsigned char) i ); setOutDisplay( (unsigned char) i, 1); setOutDisplay( (unsigned char) i, 2); setOutDisplay( (unsigned char) i, 3); setOutDisplay( (unsigned char) i, 4); setOutDisplay( (unsigned char) i, 5); for( j = 0; j< 1000; j++) { if( !test_mode ) return; setMemory( 0xFB, getMemory( 0xFB, 0 ),0 ); setMemory( 0xFC, getMemory( 0xFC, 0 ),0 ); } } for( i = 0x10; i < 0x100 ; i = i + 0x10 ) { if( !test_mode ) return; setAddressDisplay( (unsigned char) i ); setDataDisplay( (unsigned char) i ); setOutDisplay( (unsigned char) i, 1); setOutDisplay( (unsigned char) i, 2); setOutDisplay( (unsigned char) i, 3); setOutDisplay( (unsigned char) i, 4); setOutDisplay( (unsigned char) i, 5); outbusLow( 0x9F ); selectOut( 6 ); for( j = 0; j< 1000; j++) { if( !test_mode ) return; setMemory( 0xFB, getMemory( 0xFB, 0 ),0); setMemory( 0xFC, getMemory( 0xFC, 0 ),0); } outbusLow( 0 ); selectOut( 6 ); } } int main( void ) { PCMD p; initGPIO(); /* core init, clock GPIO's, interrupt system etc uart init, console interface */ clearDataPath(); /* turn all LED's off */ /* Calm flipflops */ ackFlipflops( ); interactive_mode = 1; run_mode = 0; test_mode = 0; mem_adr_toggle = 0; debounce_counter = 0; button_pressed = 0; initCmd(); /* initialize buffered command handling */ doFlispReset(); /* reset FLIS-processor */ initSystick(); __enable_irq(); while(1) { if( (( p = getCmd() ) == ((PCMD) 0) )) { if( (run_mode == 0) && (isRunActive())) run_mode = 1; else if( (run_mode>0) && (! isRunActive() ) ) run_mode = 0; if( run_mode > 0 ) { if(run_mode == 1) { if( time > 1000 ) { doStepInstruction(); time = 0; } }else if(run_mode == 2) { if( time > 100 ) { doStepInstruction(); time = 0; } }else /* run_mode = 3 */ doStepInstruction(); } if( test_mode ) { while( test_mode) doTestMode(); Reset_Handler(); } // monitor data_set and address_set switches updateAddressDisplay( 0 ); updateDataDisplay( 0 ); }else{ /* do command */ switch( (int) p->message ) { /* Commands */ case NO_COMMAND: break; case RUN_MODE: if( run_mode == 0 ){ run_mode = 1; }else{ run_mode = 0; } /* if( run_mode == 0 ){ if( isRunSlow()){ run_mode = 2; }else time = 0; }else{ run_mode = 0; } * */ break; case TEST_MODE: if( test_mode == 0 ) test_mode = 1; else{ test_mode = 0; } break; case QUIET_MODE: interactive_mode = 0; break; case INTERACTIVE_MODE: interactive_mode = 1; updateAll(); break; case GET_VERSION: if( interactive_mode ){ consoleOut ( binToAscii( MAJOR_VERSION) ); sendAscii('.'); consoleOut ( binToAscii( MINOR_VERSION) ); } ackFlipflops( ); break; break; case MEM_ADDR_H_INC: case MEM_ADDR_H_DEC: case MEM_ADDR_L_INC: case MEM_ADDR_L_DEC: updateAddressDisplay( p->message ); updateDataDisplay( 0 ); break; case MEM_DATA_H_INC: case MEM_DATA_H_DEC: case MEM_DATA_L_INC: case MEM_DATA_L_DEC: updateDataDisplay( p->message ); break; case FLISP_RESET: doFlispReset(); break; case STEP_INSTRUCTION: /* check hardware switch */ if( run_mode == 1) run_mode = 2; else if (run_mode == 2 ) run_mode = 3; else if( run_mode == 3 ) run_mode = 1; else doStepInstruction(); break; case MEM_DATA_SET: if( isDataSetMode() ) { if( isAddressAutoMode()) setMemory(autoaddress,modifydata,0); // memory[autoaddress]= modifydata; else setMemory(address,modifydata,0); // memory[address]= modifydata; } break; case MEMORY_WRITE: setMemory(p->p1, p->p2, 0); if( interactive_mode ) updateAll(); break; case MEMORY_READ: sendAsAscii( getMemory( p->p1, 0 ) ); sendEOT(); break; case REGISTER_WRITE: setFlispRegisterValue(p->p1, p->p2); if( interactive_mode ) updateAll(); break; case REGISTER_READ: sendAsAscii( getFlispRegisterValue( p->p1 ) ); sendEOT(); break; } } } return 0; /* never reached */ }