CPCWiki forum

General Category => Programming => Topic started by: Ast on 19:59, 11 December 14

Title: PPI
Post by: Ast on 19:59, 11 December 14
Hello,

I've just done a little proggy with keyboard tests (No firmware)
My problem is how can i do to delete keyboard repetition ?
For example, to see if it worked, i decided to test the right key.
In fact, when you press the right key, it increment A register 1 by 1. So the problem is :
First Key right pressed : A=1
Second Key right pressed : A=6
Third Key right pressed : A=16
...etc...
This is due to keyboard repetition and I've no idea about how to cancel that repetition. Who could help me ?

Title: Re: PPI
Post by: TFM on 20:01, 11 December 14
What do you mean with repetition?
could you "just" set A back to 0?

Title: Re: PPI
Post by: Ast on 20:04, 11 December 14
yes i try to put set 1,a (after my test key) but it's not working... :-\
Title: Re: PPI
Post by: TFM on 20:05, 11 December 14
Can you place the source here?



Title: Re: PPI
Post by: Ast on 20:09, 11 December 14
Code is like that :


          ld d,0 ; keyboard line
          bit 1,a ; test bit 1-> Right Key
          jr nz,nextkey ; if a=1 go to next key
          set 1,a ; Put bit 1 to 1
          call rightkey  ; Rkey is pressed so goto RightKey proggy

nextkey

Title: Re: PPI
Post by: Ast on 20:10, 11 December 14
Same times... We're always connected... :laugh:
Title: Re: PPI
Post by: arnoldemu on 20:23, 11 December 14
Remember old keyboard state.
Get new state.
Use xor to give changes.
Then check New is pressed or not as you need.

Keyboard repeat is made by firmware.
Hardware says if key pressed or not, but may be pressed for more than one frame.
So you need to manage it.
Title: Re: PPI
Post by: Ast on 20:27, 11 December 14
I Know that but my problem is how to do it? I've ever done many tests without any victory...  :'(
Title: Re: PPI
Post by: arnoldemu on 20:40, 11 December 14
Quote from: Ast on 20:27, 11 December 14
I Know that but my problem is how to do it? I've ever done many tests without any victory...  :'(



loop:
ld b,&f5
l1:
in a,(c)
rra
jr nc,l1

;; wait until vsync is over
halt

halt

;; store current into old. it is from previous frame.
ld hl,cur_keyboard
ld de,old_keyboard
ld bc,10
ldir

;; read new keyboard state into cur_keyboard
call read_keyboard

ld a,(old_keyboard+9)
ld c,a
ld a,(cur_keyboard+9)
xor c
jr z,no_change

ld a,(cur_keyboard+9)
bit 1,a
jr z,no_press

;; press

no_press:

no_change:


jp loop






old_keyboard:
defs 10
cur_keyboard:
defs 10


a bit like that.

read_keyboard reads keyboard using ppi, it uses cpl, so that a key is pressed if bit value is 1.
Hardware normally returns bit value of 0 if key is pressed.

The above code remembers old. It does xor to know if there is a change. It then looks for a press.

So for the code to trigger, it sees the first time you press the key and will not repeat if you hold the key down.

EDIT: To work with release change this



ld a,(cur_keyboard+9)
bit 1,a
jr z,no_press


to


ld a,(cur_keyboard+9)
bit 1,a
jr nz,no_press


want to know if a key is held?


ld a,(old_keyboard+9)
ld c,a
ld a,(cur_keyboard+9)
and c
bit 1,a
jr nz,not_held

;; held


To be held, key must be pressed for 2 frames or more.


Title: Re: PPI
Post by: Ast on 21:08, 11 December 14
I'm going to make a try, and I came back to tell you if it works... thanks.
Title: Re: PPI
Post by: TFM on 21:30, 11 December 14
Quote from: Ast on 20:09, 11 December 14
Code is like that :


          ld d,0 ; keyboard line
          bit 1,a ; test bit 1-> Right Key
          jr nz,nextkey ; if a=1 go to next key
          set 1,a ; Put bit 1 to 1
          call rightkey  ; Rkey is pressed so goto RightKey proggy

nextkey



Looks perfect to me!

Title: Re: PPI
Post by: Ast on 21:47, 11 December 14
So it works... Here comes the part of code I used (Hope it will help someone...who knows?)


main     ld b,#f5
           in a,(c)
           rra
           jr nc,main+2
;
           ld hl,oldstate
           ld de,currentstate
           ld bc,10                ; if you use all the keyboard lines
           ldir
;
Right
          ld d,0                   ; which line? d=Line 0
          call keyb               ; d=line / a=State (0=Nokey/1=KeyPressed)
          ld (oldstate+0),a    ; save OldState in line 0
          ld c,a                   ; save OldState in c
          ld a,(currentstate+0)
          xor c
          jr z,Left                 ; if a=0 then left Key
;
          ld a,c                    ; take old state
          bit 1,a                   ; Bit 1=Right Key
          jr nz,Left                ; if key isn't pressed go to the next keyboard test
;
          call Code_Right        ;  Execute Code_Right
;
Left     
          ld d,1                     ; line 1
          call keyb
          ld (oldstate+1),a      ; save oldstate in line 1
...etc...


Thanks to ArnoldEmu & TFM for Help !

May the Force be with U.


Title: Re: PPI
Post by: Ast on 21:51, 11 December 14
Quote from: TFM on 21:30, 11 December 14

Looks perfect to me!

That's what i do first, but it doesn't work...
Title: Re: PPI
Post by: Rhino on 23:18, 11 December 14
A little idea for extended keyboard info:


    ;assuming that a = 1 if the fire key is pressed and 0 if not pressed

    rrca
    ld    a,(fireKeyCode)
    adc    a,a    ; a = a<<1 + c
    and    3     ; keep only bits 0 and 1
    ld    (fireKeyCode),a

    ; posible A values here

    ; 0 = no pressed
    ; 1 = just pressed
    ; 2 = just released
    ; 3 = keep pressed

    bit    0,a
    jr    nz/z, pressed / no_pressed

    cp    1
    jr    z, just_pressed

    cp    2
    jr    z, just_released

    cp    3
    jr    z, keep_pressing

Title: Re: PPI
Post by: Ast on 00:22, 12 December 14
why not ? another idea ?
Title: Re: PPI
Post by: arnoldemu on 10:02, 12 December 14
Quote from: Rhino on 23:18, 11 December 14
A little idea for extended keyboard info:


    ;assuming that a = 1 if the fire key is pressed and 0 if not pressed

    rrca
    ld    a,(fireKeyCode)
    adc    a,a    ; a = a<<1 + c
    and    3     ; keep only bits 0 and 1
    ld    (fireKeyCode),a

    ; posible A values here

    ; 0 = no pressed
    ; 1 = just pressed
    ; 2 = just released
    ; 3 = keep pressed

    bit    0,a
    jr    nz/z, pressed / no_pressed

    cp    1
    jr    z, just_pressed

    cp    2
    jr    z, just_released

    cp    3
    jr    z, keep_pressing



if you hold it for more than 3 it will wrap back to 0 and think you haven't pressed it?

better?

rrca
    ld    a,(fireKeyCode)
    adc    a,a    ; a = a<<1 + c
   cp 3
jr nz,ll1
ld a,3   
ll1:
ld    (fireKeyCode),a
Title: Re: PPI
Post by: arnoldemu on 10:03, 12 December 14
Quote from: arnoldemu on 10:02, 12 December 14
if you hold it for more than 3 it will wrap back to 0 and think you haven't pressed it?

better?

rrca
    ld    a,(fireKeyCode)
    adc    a,a    ; a = a<<1 + c
   cp 3
jr nz,ll1
ld a,3   
ll1:
ld    (fireKeyCode),a


EDIT: What happens if you release it?
firekeycode is not reset, so it doesn't see the press again?
Title: Re: PPI
Post by: Rhino on 17:15, 12 December 14
Quote from: arnoldemu on 10:02, 12 December 14
if you hold it for more than 3 it will wrap back to 0 and think you haven't pressed it?

better?

rrca
    ld    a,(fireKeyCode)
    adc    a,a    ; a = a<<1 + c
   cp 3
jr nz,ll1
ld a,3   
ll1:
ld    (fireKeyCode),a


Hi,

The idea is that the bit 0 of the extended key status code is the current key state and bit 1 is the key state in the prev frame:

frame 1 -> key no pressed (0) -> extended key value = 0 (no pressed)
frame 2 -> key pressed (1) -> extended key value = 1 (just pressed)
frame 3 -> key pressed (1) -> extended key value = 3 (keep pressing)
frame 4 -> key pressed (1) -> extended key value = 3 (keep pressing)
frame 5 -> key no pressed (0) -> extended key value = 2 (just released)
frame 6 -> key no pressed (0) -> extended key value = 0 (no pressed)

In my example code, "and 3" avoid the problem you mean:

    ; a = 0 if fire is not pressed and 1 if pressed

    rrca            ; c = a
    ld    a,(fireKeyCode)
    adc    a,a    ; a = a<<1 + c
    and    3      ; keep only bits 0 and 1
    ld    (fireKeyCode),a   ; fireKeyCode possible values = 0,1,2 or 3

   



Title: Re: PPI
Post by: Rhino on 17:23, 12 December 14
Quote from: arnoldemu on 10:03, 12 December 14
EDIT: What happens if you release it?
firekeycode is not reset, so it doesn't see the press again?

While executing the code on each frame, the extended key status will be updated.
However, after a pause while loading or similar, you may want to put the extended key status to 0.
Title: Re: PPI
Post by: opqa on 13:57, 03 January 15
There are several solutions to this "problem" depending on what you need.
This is the code I use in Yagol to scan the whole keyboard in a fast way. First I reserve some space in memory for two keyboard bitmaps.


align 32
.keybmapraw
ds 10,&ff
align 16
.keybmapfiltered
ds 10


The first one will store the raw keyboard bitmap, like reading the keyboard directly. The second one will store a filtered version that will use the xor technique described by arnoldemu to detect changes, whenever a key is first pressed, it will set the bit associated to that key. IIRC those two bitmaps are only updated every 8 frames in the current version of the program, enough for my needs. This is done during the interrupt path. The code that does it is the following:


; Scan keyboard
.scankeyb
ld bc,&f440
ld hl,keybmapraw

repeat 9

in a,(c)
ld d,a
xor (hl)
and (hl)
set 4,l
or (hl)
ld (hl),a
res 4,l
ld (hl),d
inc l

inc c
ld b,&f6
out (c),c
ld b,&f4

rend

in a,(c)
ld d,a
xor (hl)
and (hl)
set 4,l
or (hl)
ld (hl),a
res 4,l
ld (hl),d

ld bc,&f640
out (c),c
ret


This scans the whole keyboard, loops are unrolled for speed (note the use of "repeat" macro). I don't remember the whole details but also note that the PPI is already pre-initialized for keyboard scanning (the program doesn't use any sound so it's always in this state).

During the program, whenever I need to read the keyboard I just check those memory maps instead of directly reading the hardware. Also note that in the filtered keybmap, the same process that checks whether some key has been pressed has the responsibility to clear its corresponding bit when it has finished the action associated to it. Otherwise this bit will stay high forever no matter the key has already been released. These behaviour could be avoided within the scanning keyboard routine, but it would make it slower and as it is now it was OK for my needs.
Title: Re: PPI
Post by: EgoTrip on 14:43, 03 January 15
I was expecting this thread to be spam for some reason, for the PPI refunds.
Title: Re: PPI
Post by: sigh on 16:48, 03 January 15
Quote from: EgoTrip on 14:43, 03 January 15
I was expecting this thread to be spam for some reason, for the PPI refunds.

Exactly what I thought!
Powered by SMFPacks Menu Editor Mod