Process keyboard input
Hello!
I have this program that mostly works when using FlexProp with the internal PST terminal on MacOS. The only issue I have is with the comparison:
cmp data_1, ##$0A wz
if_z jmp #.send_crlf
If I remove the if_z, then I get the correct output. If the "a" key is hit for example, it prints to the screen, is transfered to the buffer and then also prints that buffer. I'm not sure if I should be doing a comparison against the against the expected key (LF in this case on MacOS) or something else.
Full code:
' sets the system clock frequency
_CLKFREQ = 200_000_000
' set the receiving pin for input to the P2 microcontroller
RX_PIN = 63
' set the transmission pin for output from the P2 microcontroller
TX_PIN = 62
' set the baud mode to support 2000000 baud
BAUD_RATE = 2_000_000
' set the serial clock period for the baud rate based on the system clock frequency (_CLKFREQ)
SERIAL_CLOCK = ( _CLKFREQ / BAUD_RATE )
' calculate a bit period value for the serial communication baud rate.
BIT_PERIOD = (( SERIAL_CLOCK << 16 ) & $FFFFFC00 ) + ( 32 - 1 )
dat
org 0 ' start assembling code from address 0
asmclk ' use the system clock (_CLKFREQ) for timing-related calculations
' Configure RX smart pin
wrpin ##(P_ASYNC_RX | P_HIGH_15K ), #RX_PIN ' configure the RX pin as a smart pin for asynchronous serial reception
wxpin ##BIT_PERIOD, #RX_PIN ' set the correct timing for receiving bits at the correct speed
dirh #RX_PIN ' sets the direction of the RX pin to high
' Configure TX smart pin
wrpin ##(P_ASYNC_TX | P_OE), #TX_PIN ' configure the TX pin as a smart pin for asynchronous serial transmission
wxpin ##BIT_PERIOD, #TX_PIN ' set the correct timing for transmitting bits at the correct speed
dirh #TX_PIN ' sets the direction of the TX pin to high
' Initialize buffer and pointers
mov buf_ptr, #input_buffer ' Initialize buffer pointer
.process_key
.get_key
testp #RX_PIN wc ' test the state of RX_PIN and update the carry flag
if_nc jmp #.get_key ' Wait until a key is pressed
rdpin data_1, #RX_PIN ' Read received byte/keypress
' Echo the received byte back to the terminal
wypin data_1, #TX_PIN ' Echo received byte/keypress immediately
.send_key
' Store the received byte in the buffer
wrbyte data_1, buf_ptr
add buf_ptr, #1 ' Move buffer pointer to next position
cmp data_1, ##$0A wz
if_z jmp #.send_crlf
jmp #.process_key ' Process more keys
.send_crlf
' Send LF (0x0A)
mov data_1, ##$0A
wypin data_1, #TX_PIN
waitx ##5000
' Null-terminate the buffer
wrbyte #0, buf_ptr
' Print the buffer
mov print_ptr, #input_buffer
call #print_buffer
' Reset buffer pointer
mov buf_ptr, #input_buffer
jmp #.process_key
' Print Buffer Subroutine (Simplified)
print_buffer
' Start reading buffer
mov print_ptr, #input_buffer ' Initialize the print pointer
.loop_print
rdbyte data_2, print_ptr ' Read the byte from the buffer
cmps data_2, #0 wz ' Check if it's a null terminator (0x00)
if_z jmp #.end_print ' If null terminator, end printing
' Echo the character back (print it)
wypin data_2, #TX_PIN ' Send the character via TX
' Move pointer to next byte
add print_ptr, #1
jmp #.loop_print ' Loop to print next byte
.end_print
ret
' Reserve space in memory for variables/data
data_1 res 1
data_2 res 1
tmp res 1
debug_char res 1 ' Reserved space for debugging
line_num res 1 ' Stores the current line number
col_num res 1 ' Stores the current column number
' Reserve space for input buffer (32 bytes)
input_buffer res 32
buf_ptr res 1 ' Buffer pointer
print_ptr res 1 ' Pointer used for printing the buffer
Comments
Chances are that what is typed is correct for printing also. ie: Don't need an end of line check for printing typed text.
PS: Printing the hex codes of each character might help you understand any confusion. That way you get to see all the non-printables.
Hi @evanh
Correct, it is printing and going to the newline via line (at least for the PST terminal). I still just want to capture the newline and examine it.
I'll give the hex printing a shot! I have some code that I can take from the double dabble code I had in another thread. I just think I need to figure out what shr I need to do at this point for the high/low nibbles. Thank you!
I tried the hex stuff. Seems to be a little off though. I changed it up abit to see if could get the ascii to print. If data_1 comes in from rdpin then print seems to out put -u1. However, if I use a a mov temp, #"a" for the direct assignment I get the expected 61 as output. So, it must be something with
Something with the initial pin setup.
Something with data_1 either when doing rdpin data_1, #RX_PIN
Something with converting ASCII coming from the keyboard.
Hi,
Do you really want to receive 32bit codes instead of 8 bit chars?
You might want to Check the
Wxpin. Statement.
Cheers Christof
Wow, this was it. The printing worked because rdpin reads the full 32bits regardless from what i can tell, but all the code after that went haywire. Doing 8 bits makes it simpler to get the lower 8 bits, which is all i need. I think i solved it but cleaning up the code a bit before reposting solution.
I think i got it working. It could probably use some improvement or optimization though.
I had to change this
BIT_PERIOD = (( SERIAL_CLOCK << 16 ) & $FFFFFC00 ) + ( 32 - 1 )
to this
BIT_PERIOD = (( SERIAL_CLOCK << 16 ) & $FFFFFC00 ) + ( 8 - 1 )
Afterwards though I had to get the lower 8 bits, pretty sure the higher ones probably contain garbage i didn't need.
shr data_1, #24 ' Extract the received byte and data_1, #$FF ' Ensure only the lower 8 bits are used
I noticed that printing the buffer was only printing two characters so I added a short delay inside the loop:
rdbyte data, print_ptr ' Read a byte cmp data, #0 wz ' Check if it's null terminator if_z jmp #.end_print ' If null, stop wypin data, #TX_PIN ' Print character waitx ##5000 ' Short delay to see the output
The final result is listed here:
' sets the system clock frequency _CLKFREQ = 200_000_000 ' set the receiving pin for input to the P2 microcontroller RX_PIN = 63 ' set the transmission pin for output from the P2 microcontroller TX_PIN = 62 ' set the baud mode to support 2000000 baud BAUD_RATE = 2_000_000 ' set the serial clock period for the baud rate based on the system clock frequency (_CLKFREQ) SERIAL_CLOCK = ( _CLKFREQ / BAUD_RATE ) ' calculate a bit period value for the serial communication baud rate. BIT_PERIOD = (( SERIAL_CLOCK << 16 ) & $FFFFFC00 ) + ( 8 - 1 ) dat org 0 ' start assembling code from address 0 asmclk ' use the system clock (_CLKFREQ) for timing-related calculations ' Configure RX smart pin wrpin ##(P_ASYNC_RX | P_HIGH_15K), #RX_PIN ' configure the RX pin as a smart pin for asynchronous serial reception wxpin ##BIT_PERIOD, #RX_PIN ' set the correct timing for receiving bits at the correct speed wypin #1, #RX_PIN ' Enable the smart pin dirh #RX_PIN ' sets the direction of the RX pin to high ' Configure TX smart pin wrpin ##(P_ASYNC_TX | P_OE), #TX_PIN ' configure the TX pin as a smart pin for asynchronous serial transmission wxpin ##BIT_PERIOD, #TX_PIN ' set the correct timing for transmitting bits at the correct speed wypin #1, #TX_PIN ' Enable the smart pin transmitter dirh #TX_PIN ' sets the direction of the TX pin to high mov buf_ptr, #input_buffer ' Initialize buffer pointer .process_key .get_key testp #RX_PIN wc ' Check if data is ready on RX_PIN if_nc jmp #.get_key ' Wait until a key is pressed rdpin data, #RX_PIN ' Read received byte shr data, #24 ' Extract the received byte and data, #$FF ' Ensure only the lower 8 bits are used wypin data, #TX_PIN ' Echo the received character wrbyte data, buf_ptr ' Store the received byte in the buffer add buf_ptr, #1 ' Move buffer pointer to next position .send_key cmp data, ##$0D wz ' Test if data equals 'CR' (carriage return) if_z jmp #.send_crlf ' If 'CR' is pressed, process the buffer jmp #.process_key ' Continue to process more keys .send_crlf wypin ##$0A, #TX_PIN ' Send LF (0x0A) in order to go to the next line wrbyte #0, buf_ptr ' Null-terminate the buffer call #.print_buffer ' Print the buffer content mov buf_ptr, #input_buffer ' Reset buffer pointer jmp #.process_key ' Return to processing more keys .print_buffer mov print_ptr, #input_buffer ' Start at the beginning .loop_print rdbyte data, print_ptr ' Read a byte cmp data, #0 wz ' Check if it's null terminator if_z jmp #.end_print ' If null, stop wypin data, #TX_PIN ' Print character waitx ##5000 ' Short delay to see the output add print_ptr, #1 ' Move to next character jmp #.loop_print .end_print ret ' Reserve space in memory for variables/data data res 1 input_buffer res 1 ' Reserve space for input buffer (32 bytes) buf_ptr res 1 ' Buffer pointer print_ptr res 1 ' Pointer used for printing the buffer
It works fine in PST terminal but not in the ANSI terminal. I'm still using FlexProp for MacOS. I may look into this later to see what needs to be done for ANSI terminal.
Thanks @evanh and @"Christof Eb."!
EDIT: I just realized I need to use the escape codes for the built in ANSI terminal.
Some observations while reading your code:
1) The right shift inserts zeros, so the following AND is not needed: shr data, #24 ' Extract the received byte ' and data, #$FF ' Ensure only the lower 8 bits are used 2) To wait while sending out the Character, wait for the Done-Flag, instead of a fixed delay: wypin data, #TX_PIN ' Print character ' waitx ##5000 ' Short delay to see the output nop '1 Instruction delay after wypin needed .waittx testp #TX_PIN wc 'wait until tx empty flag set if_nc jmp #.waittx 3) Your input_buffer is placed quite random in the hubram, because you use the cogram address but access the hubram. Replace all the mov buf_ptr, #input_buffer with: mov buf_ptr, ##@input_buffer and use RES 8 for a input_buffer of 32 bytes. (RES reserves longs, so 8*4 bytes) 4) You use often ##Constant for 8 bit constants like $0D, $0A. This adds an unnessery instruction, because constants up to 511 can be included directly into the instruction. Just use only one # (#Constant). 5) Maybe the ANSII Terminal needs a CR+LF for a new line. Try to write $0D and then $0A into the input buffer.
Andy
Hi @Ariba!
Wow, thank you so much! I posted in another thread about PSRAM and going back to learn some basics here. This helps a lot. I'm going to go back and clean up code and respost, just in case someone else learning propeller 2 assembly comes behind me with the same questions.