OLED Display Screen Lock Issue
Hi Everyone,
I'm having an issue with my OLED display (Color OLED Display Module, 96x64 from Parallax - uses SSD1331 driver chip) locking up on my test box (using the P1 chip). It only ever does it when the test box is in what has been termed "Bit Whack Mode." In this mode the test box (Prop) is acting like a bit whacker for driving attached microelectronic parts using SPI or TTL. There is a USB connection between the computer and the Prop. Originally the issue was that when the test box was not connected to the computer via USB and Bit Whack Mode was entered into, the exit command (a single button press) would not fully work (it always works, and still does, no matter what length of time test box is in Bit Whack Mode if the USB connection with the computer is present). Through fleshing the issue out, I realized that the exit command was partially working by kicking the test box out of Bit Whack Mode (as I could navigate to another mode, evidenced by the LED Bar lighting up as it would in a different mode depending on button presses) but the OLED screen was not clearing. So from that point forward, no matter what mode I was in, no matter what was supposed to be written to the OLED screen, it would always say "Bit Whack," meaning the OLED screen was locked up.
I thought this was interesting since there has never been an issue in any of the other modes, no matter what length of time the test box was in the other mode inactive. It seemed reasonable that part of the issue was the lack of a USB connection. In Bit Whack Mode, the test box is continuously looking for a command from the computer (using Full Duplex Serial), but without the USB connection it never gets anything and the OLED locks up. I tried to think of a way to trick the test box into thinking that there was a USB connection, but I wasn't sure how to trick it into thinking there was 5V and ground coming through the USB port. So I took another tact, keeping the OLED screen busy so that it wouldn't lock up. I added in the repeat loop for this mode a command to write spaces to the OLED screen in every looping. I did it in such a way that it wouldn't interfere with "Bit Whack" being written to the screen but it would still have something continuously written to it. This seemed to work. And it didn't cause too much of a delay for when the test box was actually connected to the computer via USB and receiving data to drive a part. But upon further testing I found that the problem was still there to a degree. The fix worked really well for the first 10-15 seconds in Bit Whack Mode with no USB connected. But from 15-25 seconds, 2-3 button clicks are required for the exit to work, not just one. And after 25 seconds the OLED screen is completely locked up and the prop has to be reset. My initial thought is that the writing of spaces to the OLED screen to keep it from locking up, yes fixes the problem for a little bit, but causes timing issues in the loop that become more pervasive as time in the mode increases.
Can anyone provide any insights into this issue? I would ideally like to explore a more sustainable fix for the OLED locking up in first place with no USB connection, but will be satisfied if we can brainstorm a way to make my pseudo fix in writing spaces to the OLED screen work better. Thank you!
Posted below are two versions of the Bit Whack Mode spin code. The first is the original in which I am not writing spaces continuously to the OLED and it is locking up as soon as Bit Whack mode is entered into without a USB connection. The second is that code with the OLED being continuously written to with spaces.
V.1
PUB Bit_Whacker_Mode | ch {will need to have lines connected to LED's for the control lines to the part} OLED.clearDisplay outa[LED7..LED0]~~ OLED.write1x6String(String("Bit"),3,15,0,OLED#Yellow,OLED#BLACK) OLED.write1x6String(String("Whack"),5,0,32,OLED#Yellow,OLED#BLACK) misc.delay(1000) input_buff_index := -1 repeat if misc.ChkBtnPulse(btn, 0, 50) OLED.clearDisplay return ' attempt to retrieve character from serial terminal ch := serial.rxcheck OLED.write1x6String(String(" "),1,0,0,OLED#Yellow,OLED#BLACK) {{writing space to prevent screen from locking up when test box not connected to USB in Bit Whack Mode}} ' character ready in receive buffer? if (ch <> -1) 'input_buff_index++ ' process character, test for carriage return, or basic EDITing characters like back space case ch ASCII_LF, ASCII_CR: ' return ' print the buffer if (input_buff_index > -1) ' at this point we have the command buffer, so we can parse it ' copy it bytemove( @tok_buff, @input_buff, ++input_buff_index ) ' null terminate it tok_buff[ input_buff_index ] := 0 tok_buff_index := input_buff_index ' reset buffer input_buff_index := -1 ' tokenize input string num_tokens := 0 ' start the tokenization of the string (this function mimics the C strtok_r function more or less strtok_r(@tok_buff, string(","), @token_ptr) ' continue tokenization process now that first token has been found repeat while (token_ptr <> NULL) ' upcase the token before insertion StrUpper( token_ptr ) ' insert token into token array tokens[ num_tokens++ ] := token_ptr ' get next token strtok_r( NULL, string(","), @token_ptr) ' end repeat tokenization... ' // end if buffer valid ' // Now process command in large if, elseif, else chain ' each "if" attempts to process a different command, if no ' command is found then user typed it wrong or its not supported ' and an error is emmited. Each command passes parameters to the COG ' running the specific driver being requested; NTSC, VGA, etc. ' the full functionality of each driver is NOT exposed, only a subset to ' illustrate the idea of use the Prop as a slave processor controlled by a ' serial communications stream in ASCII... {{ First process "local" client commands for terminal. These include requests to the terminal such as clear the screen, help, etc. The remaining commands are "remote commands" that are processed and then issued to the "worker" cores running the respective drivers for video, vga, audio, etc. }} ' clear the terminal screen command if ( strcomp( tokens[0], string("C") ) ) serial.txstringnl( string("OK")) OLED.clearDisplay OLED.write1x6String(string("OK"),2,15,0,OLED#Yellow,OLED#BLACK) elseif ( strcomp( tokens[0], string("O") )) serial.txstringnl( string("OK")) DataS := ( tokens[2] ) Data := StrToDec(DataS) Decimal := sn.decf(Data, 5) ifnot DataX == Data OLED.write1x6String(Decimal,5,0,0,OLED#Yellow,OLED#BLACK) outa[LED0] := !((Data & %00000001)) outa[LED1] := !((Data & %00000010) >> 1) outa[LED2] := !((Data & %00000100) >> 2) outa[LED3] := !((Data & %00001000) >> 3) outa[LED4] := !((Data & %00010000) >> 4) outa[LED5] := !((Data & %00100000) >> 5) outa[LED6] := !((Data & %01000000) >> 6) outa[LED7] := !((Data & %10000000) >> 7) DataX := Data ' print prompt serial.txstring( @prompt ) ' editing commands, for now just backspace, later you could add more advanced terminal based editing ' but the trick is to keep the buffer on the client side sync'ed with the terminal's display! ASCII_BS: ' backspace ' insert null if (input_buff_index => 0) input_buff[ input_buff_index-- ] := ASCII_NULL ' echo character serial.tx( ch ) other: ' insert character into command buffer for processing input_buff[ ++input_buff_index ] := ch ' echo character to terminal (terminal must be in non ECHO mode, otherwise you will see input 2x!) 'serial.tx( ch )
V.2
PUB Bit_Whacker_Mode | ch OLED.clearDisplay outa[LED7..LED0]~~ OLED.write1x6String(String("Bit"),3,15,0,OLED#Yellow,OLED#BLACK) OLED.write1x6String(String("Whack"),5,0,32,OLED#Yellow,OLED#BLACK) misc.delay(1000) input_buff_index := -1 repeat if misc.ChkBtnPulse(btn, 0, 50) OLED.clearDisplay return ' attempt to retrieve character from serial terminal ch := serial.rxcheck OLED.write1x6String(String(" "),1,0,0,OLED#Yellow,OLED#BLACK) {{writing space to prevent screen from locking up when test box not connected to USB in Bit Whack Mode}} ' character ready in receive buffer? if (ch <> -1) 'input_buff_index++ ' process character, test for carriage return, or basic EDITing characters like back space case ch ASCII_LF, ASCII_CR: ' return ' print the buffer if (input_buff_index > -1) ' at this point we have the command buffer, so we can parse it ' copy it bytemove( @tok_buff, @input_buff, ++input_buff_index ) ' null terminate it tok_buff[ input_buff_index ] := 0 tok_buff_index := input_buff_index ' reset buffer input_buff_index := -1 ' tokenize input string num_tokens := 0 ' start the tokenization of the string (this function mimics the C strtok_r function more or less strtok_r(@tok_buff, string(","), @token_ptr) ' continue tokenization process now that first token has been found repeat while (token_ptr <> NULL) ' upcase the token before insertion StrUpper( token_ptr ) ' insert token into token array tokens[ num_tokens++ ] := token_ptr ' get next token strtok_r( NULL, string(","), @token_ptr) ' end repeat tokenization... ' // end if buffer valid ' // Now process command in large if, elseif, else chain ' each "if" attempts to process a different command, if no ' command is found then user typed it wrong or its not supported ' and an error is emmited. Each command passes parameters to the COG ' running the specific driver being requested; NTSC, VGA, etc. ' the full functionality of each driver is NOT exposed, only a subset to ' illustrate the idea of use the Prop as a slave processor controlled by a ' serial communications stream in ASCII... {{ First process "local" client commands for terminal. These include requests to the terminal such as clear the screen, help, etc. The remaining commands are "remote commands" that are processed and then issued to the "worker" cores running the respective drivers for video, vga, audio, etc. }} ' clear the terminal screen command if ( strcomp( tokens[0], string("C") ) ) serial.txstringnl( string("OK")) OLED.clearDisplay OLED.write1x6String(string("OK"),2,15,0,OLED#Yellow,OLED#BLACK) elseif ( strcomp( tokens[0], string("O") )) serial.txstringnl( string("OK")) DataS := ( tokens[2] ) Data := StrToDec(DataS) Decimal := sn.decf(Data, 5) ifnot DataX == Data OLED.write1x6String(Decimal,5,0,0,OLED#Yellow,OLED#BLACK) outa[LED0] := !((Data & %00000001)) outa[LED1] := !((Data & %00000010) >> 1) outa[LED2] := !((Data & %00000100) >> 2) outa[LED3] := !((Data & %00001000) >> 3) outa[LED4] := !((Data & %00010000) >> 4) outa[LED5] := !((Data & %00100000) >> 5) outa[LED6] := !((Data & %01000000) >> 6) outa[LED7] := !((Data & %10000000) >> 7) DataX := Data ' print prompt serial.txstring( @prompt ) ' editing commands, for now just backspace, later you could add more advanced terminal based editing ' but the trick is to keep the buffer on the client side sync'ed with the terminal's display! ASCII_BS: ' backspace ' insert null if (input_buff_index => 0) input_buff[ input_buff_index-- ] := ASCII_NULL ' echo character serial.tx( ch ) other: ' insert character into command buffer for processing input_buff[ ++input_buff_index ] := ch ' echo character to terminal (terminal must be in non ECHO mode, otherwise you will see input 2x!) 'serial.tx( ch )