Register

Unraveling the secrets of the KEYSC

Discuss issues related to Calculator Hacking/Modding.
Member
User avatar
Posts: 39
Joined: Fri Aug 21, 2015 11:54 am
Location: France
Calculators: Casio fx-9750GII, Casio fx-9750GII (SH4), Casio fx-9860GII, Casio fx-CG50

Unraveling the secrets of the KEYSC

Postby lephe » Tue Aug 14, 2018 9:21 pm

Hi everyone :D

After facing quantum difficulties implementing a driver for the SH7305 KEYSC (which ought to be trivial! :) ), I decided to look seriously into the matter and gather documentation for this module. As there is no SH-4A info in Simon's chm [14195], I wish to use this topic as a repository for SH7305 KEYSC-related information until I can write my own piece of documentation.

Basically I'd like to hear about everything we know about this interface. :D

I'll start right away with my quantum behaviors: accessing the KEYSC registers inside or outside an interrupt handler seems to give different results. :o This will be in my following post (to keep things in order).

The repository: what we know about the KEYSC

The KEYSC module is a customized one. The 6 words at a44b'0000 indicate the key hit status (in little-endian format, one byte per actual keyboard row). [14191]

The a44b'0000 interface only gives accurate results if its data is accessed often enough; according to empirical experiments, 64 Hz is reasonable but 16 Hz is definitely not enough. [20592]

The key matrix can be accessed through ports Z, M and N. The method is the same as CheckKeyRow() for SH3-based models. [14193]

The initialization phase takes place in syscall 0x117. Apparently it hasn't been analyzed in-depth for now. [14205]

On the fx-FD10 Pro, there is an unknown 8-bit keyboard-related register at a405'01c6, and keyboard scanning involves HIZCRB. [14193]

The KEYSC is mainly found in mobile processors, but so far the SH7305 has a unique module structure.
  • SH7231 (SH-2A, doc): KEYSC reports either pin state or key hit status (max. 16 keys)
  • SH7722 (aka. SH-MobileR, SH4AL-DSP)
  • SH7723 (aka. SH-MobileR2, SH-4A)
  • SH7724 (aka. SH-MobileR2R, SH-4A): KEYSC registers report the state of the pins
  • SH7305: KEYSC reports key hit status
Last edited by lephe on Sat Sep 15, 2018 1:03 pm, edited 1 time in total.

Member
User avatar
Posts: 39
Joined: Fri Aug 21, 2015 11:54 am
Location: France
Calculators: Casio fx-9750GII, Casio fx-9750GII (SH4), Casio fx-9860GII, Casio fx-CG50

Re: Unraveling the secrets of the KEYSC

Postby lephe » Tue Aug 14, 2018 9:22 pm

The analysis in this post has been superseded by [20592]. The relevant difference is not kernel/interrupt mode but access frequency.

As I tried to fix a bug, I found something odd but confirmed by several tests that I made: reading the KEYSC data from an interrupt handler or from the user program does not give the same results. :o

Following are two tests which I have made in a free-standing add-in on fx-9860G II. The situation is as follows:
  • Self-hosted environment, free from system interrupts
  • All interrupts disabled except timer 3 in the second test
  • No system calls except Bdisp_AllClr_VRAM(), PrintXY() and Bdisp_PutDisp_DD().

First test: read KEYSC data from "userland"

The following program is used to display the key hit status from the KEYSC in real-time. The 8 bottom rows are shown. The function keysc_userland() is called from the user program, which is non-interrupted kernel mode. All interrupts are disabled, the program stops after the active loop ends (roughly 30 seconds).

Code: Select all
void display_keys(uint8_t *keys)
{
    Bdisp_AllClr_VRAM();
    for(int r = 0; r < 8; r++) print_bin(1, r + 1, keys[r ^ 1], 8);
    Bdisp_PutDisp_DD();
}

void keysc_userland(void)
{
    volatile uint16_t *KEYSC = (void *)0xa44b0000;
    uint16_t buffer[6];

    for(int counter = 0; counter < 4000; counter++)
    {
        for(int i = 0; i < 6; i++) buffer[i] = KEYSC[i];
        display_keys(buffer);
    }
}

This program faithfully shows the hit status of all keys on the keyboard, apart from the usual shadowing effect inherent to the matrix design of the keyboard. I consider shadowing to be normal.

Conclusion: accessing KEYSC data from "userland" works as expected. :)

Second test: read KEYSC data from an interrupt handler

This new test does exactly the same thing, but data is loaded from the KEYSC in a 16-Hz timer interrupt handler. Due to the design of my TMU driver, keysc_callback executes inside the interrupt handler, with SR.RB=1, SR.BL=1 and all the usual stuff.

Also note that "buffer" from keysc_timer() is passed to the callback under the name "arg", so the callback effectively loads KEYSC data into the array.

Code: Select all
int keysc_callback(void *arg)
{
    volatile uint16_t *buffer = arg;
    volatile uint16_t *KEYSC = (void *)0xa44b0000;

    for(int i = 0; i < 6; i++) buffer[i] = KEYSC[i];
    return 0;
}

void keysc_timer(void)
{
    volatile uint16_t buffer[6];

    timer_setup(3, 2048, 0, keysc_callback, &buffer);
    timer_start(3);

    for(int counter = 0; counter < 4000; counter++)
    {
        display_keys(buffer);
    }

    timer_free(3);
}

This program fails to describe the exact state of the keyboard: when pressing several keys then releasing them (in any order), often the KEYSC will not detect all releases. Data read from the KEYSC will indicate that some of the keys are still pressed although they were actually released.

The KEYSC remains in this "inconsistent" state until a new key is pressed on the keyboard. When the new key is released, the same phenomenon can occur again. Overall it happens very often, when randomly pressing set of keys with my ten fingers it happens around 80% of the time.

Conclusion: accessing KEYSC data from an interrupt handler produces artifacts. :(

Additional notes

  • If access are made both in "user" and in interrupted mode at the same time, the KEYSC behaves normally.
Last edited by lephe on Sat Sep 15, 2018 12:57 pm, edited 1 time in total.

Member
User avatar
Posts: 39
Joined: Fri Aug 21, 2015 11:54 am
Location: France
Calculators: Casio fx-9750GII, Casio fx-9750GII (SH4), Casio fx-9860GII, Casio fx-CG50

Re: Unraveling the secrets of the KEYSC

Postby lephe » Sun Aug 19, 2018 1:01 pm

I have a trail for this problem. :D Up to now, I worked around the strange phenomenon by doing "userland" reads when invoking the keyboard functions, like my_getkey(). It worked, according to my remark in the previous post.

I then tried the function on an fx-CG50, and I found out that the workaround only works at high overclock levels.

  • In fx-CG 50 normal mode (117 MHz) and above (Ptune3's [F4] 235 MHz and [F5] 191 MHz), the workaround works. After pressing then releasing any set of keys the KEYSC indicates that the keyboard is idle.
  • In fx-CG 10/20 normal (58 MHz) and overclocked (95 MHz) modes, the workaround does not fully work and the artifacts still occur, although less often.

I have tried the same test on my fx-9860G II and I found that artifacts can occur (despite the workaround) when the processor frequency drops around 5 MHz.

Any thoughts on this? Could there be access-delay-related or electronic reasons behind this? The fact that reading fast makes the thing work is still puzzling me. :think:

Member
User avatar
Posts: 39
Joined: Fri Aug 21, 2015 11:54 am
Location: France
Calculators: Casio fx-9750GII, Casio fx-9750GII (SH4), Casio fx-9860GII, Casio fx-CG50

Re: Unraveling the secrets of the KEYSC

Postby lephe » Wed Aug 22, 2018 1:27 pm

I'm making progress! :D I explored my previous trail about using a higher access frequency to read KEYSC data.

I bumped my keyboard scan function from 16 Hz (just enough for human users) to 128 Hz.

  • On fx-9860G II, all artifacts disappeared even without the workaround, and even at the bare minimum processor frequency of 1.84 MHz. Doing 128 Hz reads in an interrupt handler is enough to get everything right for practical uses.
  • On fx-CG 50, the workaround is still needed (without it, I can't detect anything), but increasing the scan frequency seems to reduce the amount of artifacts when the overclock level is low.

I'm clearly seeing differences between the two models, which suggests that this is not exactly the same KEYSC (or it's configured differently). Since I've also observed small differences about the CPG, I'm starting to consider that it may not be exactly the same SH7305... :)

Member
User avatar
Posts: 30
Joined: Mon Oct 27, 2014 1:46 pm
Location: Japan
Calculators: Casio Cfx Series, Casio fx-9860G, Casio fx-9860GII, Casio fx-9860GII SD Power Graphic 2, Casio fx-CG10, Casio fx-CG20, Casio fx-CG50

Re: Unraveling the secrets of the KEYSC

Postby sentaro21 » Wed Aug 22, 2018 1:32 pm

Thanks for the valuable KEYSC infomation. :D

I read KEYSC directly in C.Basic, but it not use a interrupt.
So it worked well.
However it sometimes freeze with the emulator. :roll:

I'm sorry, I do not have your helpful information. :|

Member
User avatar
Posts: 39
Joined: Fri Aug 21, 2015 11:54 am
Location: France
Calculators: Casio fx-9750GII, Casio fx-9750GII (SH4), Casio fx-9860GII, Casio fx-CG50

Re: Unraveling the secrets of the KEYSC

Postby lephe » Fri Sep 07, 2018 7:45 pm

The emulator has probably yet another implementation... this is the kind of low-level things that are emulated, not simulated.

Now since TeamFX and SimonLothar provided me with some details when I worked on CheckKeyRow(), I hoped a few more details were known. Is there really nothing discovered in the documentation or through reverse-engineering? :(

Member
User avatar
Posts: 39
Joined: Fri Aug 21, 2015 11:54 am
Location: France
Calculators: Casio fx-9750GII, Casio fx-9750GII (SH4), Casio fx-9860GII, Casio fx-CG50

Re: Unraveling the secrets of the KEYSC

Postby lephe » Wed Sep 12, 2018 8:58 pm

I just made a breakthrough in understanding this problem! :D

The artifact problem may actually be entirely frequency-based.

The idea is simple: data must be read often from the KEYSC to be correct.

My original test [20580] was flawed: in interrupt mode I was reading the KEYSC at a frequency of 16 Hz while in the userland test I was doing it a full speed, nothing short of 100 kHz!

I just ran the interrupt version with a frequency bumped as high as 1024 Hz and the artifacts disappeared entirely when I tested it for a few minutes.

I have yet to experiment it on fx-CG50 or determine the limit frequency at which artifacts tend to appear, but hopefully I have found a suitable solution for this problem. The performance cost also needs to be measured, at the very least.

Now to explain this requirement of reading fast, I can speculate that the KEYSC has an internal buffer, filled automatically with time, with reading at a44b'0000 unqueuing data from the buffer. If the buffer is full, which presumably happens when waiting too long between two reads, the KEYSC may not be able to store data coming in from the I/O ports, which would explain that some key releases were not taken into account. :)

Any thoughts on this? Does anyone actually knows what the KEYSC is made of apart from this buffer? I consider disassembling the initialization syscall to have a look at what happens there.

Member
User avatar
Posts: 30
Joined: Mon Oct 27, 2014 1:46 pm
Location: Japan
Calculators: Casio Cfx Series, Casio fx-9860G, Casio fx-9860GII, Casio fx-9860GII SD Power Graphic 2, Casio fx-CG10, Casio fx-CG20, Casio fx-CG50

Re: Unraveling the secrets of the KEYSC

Postby sentaro21 » Sun Sep 16, 2018 4:17 am

Congratulations on clearing the artifact problem! :D

Although it may be wrong,
KEYSC of SH7305 and SH7724 is different implementation,
but I think that the chattering elimination circuit is implemented equally.
Is it possible that it affects it?

Member
User avatar
Posts: 39
Joined: Fri Aug 21, 2015 11:54 am
Location: France
Calculators: Casio fx-9750GII, Casio fx-9750GII (SH4), Casio fx-9860GII, Casio fx-CG50

Re: Unraveling the secrets of the KEYSC

Postby lephe » Sun Sep 16, 2018 7:18 pm

Thank you Sentaro ! :D

I'm not sure whether this is an electronic reason, because when an artifact occurs, it continues to occur indefinitely until a key is pressed. If it was caused by a delay or bounce in a signal, wouldn't it disappear after a short while?

I have determined a reasonable frequency to be 64 Hz. I have configured my kernel to run at 128 Hz on both fx-9860G II and fx-CG 50 and it works very well. I'm satisfied with this outcome because it's less hacky than having to read from userspace. :)

Junior Member
User avatar
Posts: 3
Joined: Wed Feb 13, 2019 5:44 pm
Calculators: None

Re: Unraveling the secrets of the KEYSC

Postby Yatis » Wed Feb 13, 2019 6:38 pm

I started to analyze the syscall 0x117. I have not finished yet but I retrieved some registry information between 0xa44b000c and 0xa44b001c. (some 16 bits registers)
Here is what I could find:
Code: Select all
union {
   uint16_t WORD;
   struct {
      unsigned ????????   : 1;   //set to 1 by Casio's syscall 0x117
      unsigned const       : 13;   //always 0
      unsigned ????????   : 2;   //set to 0 by Casio's syscall 0x117
   };
} 0xa44b000c;

union {
   uint16_t WORD;
   struct {
      unsigned ???????   : 1;   //set to 1 by Casio's syscall 0x117
      unsigned const      : 8;   //always 0
      unsigned ???????   : 3;   //set to 4 by Casio's syscall 0x177
      unsigned const      : 1;   //always 0
      unsigned ???????   : 3;   //set to 2 by Casio's syscall 0x117
   };
} 0xa44b000e;

union {
   uint16_t WORD;
   struct {
      unsigned const      : 4;   //always 0
      unsigned ????????   : 3;   //set to 2 by Casio's syscall 0x117
      unsigned const      : 9;   //always 0
   };
} 0xa44b0010;

union {
   uint16_t WORD;
   struct {
      unsigned const      : 15;   //always 0
      unsigned ????????   : 1;   //set to 1 by Casio's syscall 0x117
   };
} 0xa44b0012;

union {
   uint16_t WORD;
   struct {
      unsigned const      : 1;   //always 0
      unsigned ????????   : 7;   //set to 0x48 by Casio's syscall 0x117
      unsigned const      : 8;   //always 0
   };
} 0xa44b0014;

union {
   uint16_t WORD;
   struct {
      unsigned const      : 1;   //always 0
      unsigned ????????   : 15;   //set to 0 by Casio's syscall 0x117
   };
} 0xa44b0016;


union {
   uint16_t WORD;   //set to 0x0098 by Casio's syscall 0x117
} 0xa44b0018;


union {
   uint16_t WORD;
   struct {
      unsigned const      : 4;   //always 0
      unsigned ????????   : 12;   //set to 0xfff by Casio's syscall 0x117
   };
} 0xa44b001a;

union {
   uint16_t WORD;
   struct {
      unsigned const      : 8;   //always 0
      unsigned ????????   : 8;   //set to 0xff by Casio's syscall 0x117
   };
} 0xa44b001c;

Otherwise nothing very interesting for now (I did a small part of the syscall because it's big :/ ).
(I hope I didn't say anything stupid :oops: )

Next

Return to Calculator Hacking/Modding Discussions

Who is online

Users browsing this forum: No registered users and 34 guests