Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 08:45 06 Jul 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : MM2: PS2 keyboard input Cfunction

Author Message
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10209
Posted: 10:26am 28 Feb 2015
Copy link to clipboard 
Print this post

Here is a demo program using a Cfunction to read the output of a standard PS2 keyboard.

The codes sent are given in this document

The Cfunction and demo program are attached:



option explicit
option default none
cpu 48
' 28 pin
setpin 9,din ' these pins fixed to match the Cfunction - KB clock
setpin 10,din ' KB data

' 44 pin
'setpin 30,din ' these pins fixed to match the Cfunction - KB clock
'setpin 31,din ' KB data
'
dim integer i
dim s$ length 3
do
i=ps2(s$,1000,48) 'String to receive KB data, timeout in msec, CPU speed in MHz
if i=0 then print "timeout"
if i=1 then print hex$(asc(left$(s$,1)))
if i=2 then print hex$(asc(left$(s$,1))),hex$(asc(mid$(s$,2,1)))
if i=3 then print hex$(asc(left$(s$,1))),hex$(asc(mid$(s$,2,1))),hex$(asc(righ t$(s$,1)))
loop

'
CFunction ps2
00000000
27bdff60 8ca50000 03a03821 27a300a0 03a01021 ac400000 24420004 5443fffe
ac400000 34038010 3c02bf80 ac430600 8cc90004 240803e8 8cc20000 00480019
00001012 00001810 71283002 00c34021 05010005 01001821 24460007 00c2182b
00c01021 00681821 00031f40 000210c2 10a000ae 00623025 3c03bf80 3c08bf88
ac600610 8d026020 30420004 10400005 00000000 8c620610 0046102b 1440fff9
00000000 8c620610 0046102b 14400007 00000000 24a5ffff 14a0fff1 00000000
00002021 1000009e 00002821 10a0009a 3c03bf88 8c626020 30420004 1040fffd
3c02bf80 ac400610 00e04021 00003021 24090028 10000025 3c05bf88 ac400610
8ca36020 30630004 10600005 00000000 8c430610 2c632ee0 1460fff9 00000000
8c430610 2c632ee0 50600020 2402000a ac400610 8c430610 2c63000a 1460fffd
00000000 8ca36020 7c6300c0 ad030000 24c60001 ac400610 8ca36020 30630004
14600005 00000000 8c430610 2c630190 1460fff9 00000000 8c430610 2c630190
54600001 ac400610 25080004 8c430610 2c632ee0 50600005 2402000a 14c9ffd7
00000000 10000012 24020015 14c20010 24020015 24020001 a0820000 a0800001
00001821 00001021 24060008 8ce50000 00452804 00651825 306300ff 24420001
1446fffa 24e70004 1000004c a0830001 14c2001e 24020020 24020002 a0820000
a0800001 a0800002 00001821 00001021 24060008 8ce50000 00452804 00651825
306300ff 24420001 1446fffa 24e70004 a0830001 90850002 27a3002c 00001021
24070008 8c660000 00463004 00a62825 30a500ff 24420001 1447fffa 24630004
a0850002 1000002e 24020002 14c2002c 00001021 24020003 a0820000 a0800001
a0800002 a0800003 00001821 00001021 24060008 8ce50000 00452804 00651825
306300ff 24420001 1446fffa 24e70004 a0830001 90850002 27a3002c 00001021
24070008 8c660000 00463004 00a62825 30a500ff 24420001 1447fffa 24630004
a0850002 90850003 27a30058 00001021 24070008 8c660000 00463004 00a62825
30a500ff 24420001 1447fffa 24630004 a0850003 10000002 24020003 24020001
00402021 10000006 00002821 00002021 10000003 00002821 00002021 00002821
00801021 00a01821 03e00008 27bd00a0
End CFunction
'long long ps2(unsigned char d[],long long *msec, long long *cpu){
' #define tmr1con *(volatile unsigned int *)0xbf800600 //timer 1 configuration register
' #define tmr1 *(volatile unsigned int *)0xbf800610 //timer 1 counter
' unsigned int i,j,clockpin=4,datapin=8,log[40],timeout, k=*msec;
' unsigned int volatile * myport;
' myport=(volatile unsigned int *)0xbf886020;
' for(i=0;i<40;i++)log=0;
' tmr1con=0x8010; //turn on with scale 8
' timeout=(*cpu * 1000/8); //1msec setting for clock
' i=0;
' while (k>0){
' tmr1=0;
' while((*myport & clockpin)!=0 && tmr1<timeout);
' if(tmr1< timeout) break;
' k--;
' }
' if(k==0) return 0;
' while ((*myport & clockpin)==0); //wait pin to go high after the start bit
' tmr1=0;
' while (tmr1<12000 && i<40){ //loop until a timeout or all data received
' tmr1=0; //reset the timer
' while (((*myport & clockpin)!=0) && (tmr1<12000)); //wait for clock to go low
' if(tmr1<12000){
' tmr1=0;
' while(tmr1<10); //wait for mid low clock
' log=(*myport & datapin)>>3;
' i++;
' tmr1=0;
' } else break;
' while (((*myport & clockpin)==0) && (tmr1<400)); //wait for clock to go high
' if (tmr1<400) tmr1=0;
' }
' if(i==10){
' d[0]=1;
' d[1]=0;
' for(j=0;j<8;j++)d[1]|=(log[j]<<j);
' i=1;
' } else if(i==21){
' d[0]=2;
' d[1]=0;
' d[2]=0;
' for(j=0;j<8;j++)d[1]|=(log[j]<<j);
' for(j=0;j<8;j++)d[2]|=(log[j+11]<<j);
' i=2;
' } else if(i==32){
' d[0]=3;
' d[1]=0;
' d[2]=0;
' d[3]=0;
' for(j=0;j<8;j++)d[1]|=(log[j]<<j);
' for(j=0;j<8;j++)d[2]|=(log[j+11]<<j);
' for(j=0;j<8;j++)d[3]|=(log[j+22]<<j);
' i=3;
' } else i=0; //invalid pulse string
' return i;
'}
'

Edited by matherp 2015-03-01
 
Zonker

Guru

Joined: 18/08/2012
Location: United States
Posts: 767
Posted: 01:11pm 28 Feb 2015
Copy link to clipboard 
Print this post

Wow... Another Ass kickin CFunction..!

The Library keeps growing... Awesome.... I finally got the time this weekend to test the 2.4" touch display you created... Works like a champ..! We can now create small GUI apps with this...

More power to the MicroMite..!!
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9588
Posted: 01:55pm 28 Feb 2015
Copy link to clipboard 
Print this post

I can see using this quite a bit, so thanks!


QUESTION: Why did you use COM2 for the KB in the Cfunction, and not just a couple of I/O pins? This gobbles up COM2, and if you are already using it, the KB Cfunction will not work.

I am sure there was a reason, but I would love to know what it was/is.....

Serial out ports are no problem with the Cfunction that creates extra serial TXD channels, but if you need the RXD buffers(as I do), then you need both COM ports, and can't use those pins for anything else.

EDIT: Will this work on the 470 chip too? If so, which pins?(62 & 63?)Edited by Grogster 2015-03-02
Smoke makes things work. When the smoke gets out, it stops!
 
cosmic frog
Guru

Joined: 09/02/2012
Location: United Kingdom
Posts: 302
Posted: 02:41am 01 Mar 2015
Copy link to clipboard 
Print this post

Brilliant! All we need now is a cfunction for video out and we have everything.

Dave.
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 03:25am 01 Mar 2015
Copy link to clipboard 
Print this post

Video out will never be done with a Cfunction.
But look at the many LCD that can be connected and directly used from a cfuntion.
I think that is a much better way to use a controller that is meant to be a solution for embedded projects.
A big monitor or even a crt is really not a good fit.
Also the cheap car video monitors can be replaced with an even cheaper LCD.

I think any pin will work as none of the uart functionality is used.
It would be great if there is an easy way to have pin numbers as parameters, but without a lot of extra code written in the CFunction i can not see how that is done.
Having the C source code you would be able to change it if necessary.



Microblocks. Build with logic.
 
cosmic frog
Guru

Joined: 09/02/2012
Location: United Kingdom
Posts: 302
Posted: 07:13am 01 Mar 2015
Copy link to clipboard 
Print this post

Is there a link to how the cfunction works or how to make your own cfunction as it just looks like a load of hex to me.
Thanks. Dave.
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10209
Posted: 07:40am 01 Mar 2015
Copy link to clipboard 
Print this post

  Quote  Why did you use COM2 for the KB in the Cfunction, and not just a couple of I/O pins?

  Quote  EDIT: Will this work on the 470 chip too? If so, which pins?(62 & 63?)


Some people are just never satisfied

OK here is a version that will work on any pins on any of the chips. You have a little bit of work to do though . The call to the Cfunction requires you to specify the port and pin for both the KB data and KB clock inputs. To do this you need to look up the details of the mapping of the physical pin number to its actual hardware port address in the relevant Microchip datasheet.

Thus on the 64-pin MX470 pin 55 is port D07, pin 54 is port D06. To call the Cfunction use 0 for port A, 1 for port B etc. as in the example where D=3.The pin number just needs setting 1:1 i.e. D07 requires the parameters 3,7.
I've included a couple of new commands in the MX470 firmware to do this for you and hopefully Geoff will at some point include something similar in the MX170 firmware but to make this code completely portable I'm not using these in the example.

The code has been tested on the MX170 and MX470 at speeds from 10-96Mhz - it doesn't work at 5MHz. Note that you need to specify the CPU speed in the call to the Cfunction - this is only used to make the timeout last the correct amount of time.

You should use SETPIN x,DIN for the two pins used but actually this isn't essential as the default state of pins after boot is as digital inputs.

option explicit
option default none
' change these pins to match the call to the Cfunction
setpin 55,din ' KB clock
setpin 54,din ' KB data
'
dim integer i
dim s$ length 3
do
i=ps2(s$,1000,48,3,7,3,6) 'String to receive KB data, timeout in msec, CPU speed in MHz, data port number, data pin number, clock port number, clock pin number
' In this example for the 64-pin MX470 the data pin definition is 3,7 (i.e. D07=pin 55) the clock pin definition is 3,6 (i.e D06=pin 54)
if i=0 then print "timeout"
if i=1 then print hex$(asc(left$(s$,1)))
if i=2 then print hex$(asc(left$(s$,1))), hex$(asc(mid$(s$,2,1)))
if i=3 then print hex$(asc(left$(s$,1))), hex$(asc(mid$(s$,2,1))), hex$(asc(right$(s$,1)))
loop

'
CFunction ps2
00000000
27bdffd8 8fa80038 8ca90000 24020001 8fa30040 8c650000 00a22804 8d0a0000
01425004 8ceb0000 000b5a00 3c02bf88 24426020 01625821 8fa3003c 8c670000
00073a00 00e23821 03a01021 27a30028 a0400000 24420001 5443fffe a0400000
34038010 3c02bf80 ac430600 8ccd0004 240c03e8 8cc20000 004c0019 00001012
00001810 71ac3002 00c36021 05810005 01801821 24460007 00c2182b 00c01021
006c1821 00031f40 000210c2 112000aa 00623025 3c03bf80 ac600610 8ce20000
00451024 10400005 00000000 8c620610 0046102b 1440fff9 00000000 8c620610
0046102b 14400007 00000000 2529ffff 1520fff1 00000000 00002021 1000009a
00002821 51200097 00002021 8ce20000 00451024 1040fffd 3c02bf80 ac400610
00003021 10000027 24090028 ac400610 8ce30000 00651824 10600005 00000000
8c430610 2c635dc0 1460fff9 00000000 8c430610 2c635dc0 50600022 2402000a
ac400610 8c430610 2c630014 1460fffd 00000000 8d6c0000 03a61821 018a6024
8d0d0000 01ac6006 a06c0000 24c60001 ac400610 8ce30000 00651824 14600005
00000000 8c430610 2c6301f4 1460fff9 00000000 8c430610 2c6301f4 54600001
ac400610 8c430610 2c635dc0 50600005 2402000a 14c9ffd5 00000000 10000012
24020015 14c20010 24020015 24020001 a0820000 a0800001 00001821 00001021
24060008 03a22821 90a50000 00452804 00a31825 24420001 1446fffa 306300ff
10000049 a0830001 14c2001d 24020020 24020002 a0820000 a0800001 a0800002
00001821 00001021 24060008 03a22821 90a50000 00452804 00a31825 24420001
1446fffa 306300ff a0830001 90830002 00001021 24060008 03a22821 90a5000b
00452804 00a31825 24420001 1446fffa 306300ff a0830002 1000002c 24020002
14c2002a 00001021 24020003 a0820000 a0800001 a0800002 a0800003 00001821
00001021 24060008 03a22821 90a50000 00452804 00a31825 24420001 1446fffa
306300ff a0830001 90830002 00001021 24060008 03a22821 90a5000b 00452804
00a31825 24420001 1446fffa 306300ff a0830002 90830003 00001021 24060008
03a22821 90a50016 00452804 00a31825 24420001 1446fffa 306300ff a0830003
10000002 24020003 24020001 00402021 10000005 00002821 00002021 10000002
00002821 00002821 00801021 00a01821 03e00008 27bd0028
End CFunction
'
'long long ps2(unsigned char d[],long long *msec, long long *cpu, unsigned long long *dataportnum,unsigned long long *datapinnum,unsigned long long *clkportnum,unsigned long long *clkpinnum){
' #define tmr1con *(volatile unsigned int *)0xbf800600 //timer 1 configuration register
' #define tmr1 *(volatile unsigned int *)0xbf800610 //timer 1 counter
' unsigned int index,i,j,timeout, k=*msec;
' unsigned int waitbetweenpackets=24000;
' unsigned int waitforclockpinchange=500;
' i=*clkportnum * 0x100; //port addresses are spaced out at 0x100 intervals
' j=*dataportnum * 0x100;
' unsigned int clockpin=1<<*clkpinnum; //create a mask for the clock pin
' unsigned int datapin=1<<*datapinnum; //create a mask for the data pin
' unsigned char log[40];
' volatile unsigned int *dataport, *clockport;
' dataport=(volatile unsigned int *)(0xbf886020 + j); //data port read register
' clockport=(volatile unsigned int *) (0xbf886020+ i); //clock port read register
' for(j=0;j<40;j++)log[j]=0;
' tmr1con=0x8010; //turn on with scale 8
' timeout=(*cpu * 1000/8); //1msec setting for clock
' index=0;
' while (k>0){
' tmr1=0;
' while((*clockport & clockpin)!=0 && tmr1<timeout);
' if(tmr1< timeout) break;
' k--;
' }
' if(k==0) return 0;
' while ((*clockport & clockpin)==0); //wait pin to go high after the start bit
' tmr1=0;
' while (tmr1<waitbetweenpackets && index<40){ //loop until a timeout or all data received
' tmr1=0; //reset the timer
' while (((*clockport & clockpin)!=0) && (tmr1<waitbetweenpackets)); //wait for clock to go low
' if(tmr1<waitbetweenpackets){
' tmr1=0;
' while(tmr1<20); //wait for data to be established during low clock
' log[index]=(*dataport & datapin)>>*datapinnum;
' index++;
' tmr1=0;
' } else break;
' while (((*clockport & clockpin)==0) && (tmr1<waitforclockpinchange)); //wait for clock to go high
' if (tmr1<waitforclockpinchange) tmr1=0;
' }
' if(index==10){
' d[0]=1;
' d[1]=0;
' for(j=0;j<8;j++)d[1]|=(log[j]<<j);
' index=1;
' } else if(index==21){
' d[0]=2;
' d[1]=0;
' d[2]=0;
' for(j=0;j<8;j++)d[1]|=(log[j]<<j);
' for(j=0;j<8;j++)d[2]|=(log[j+11]<<j);
' index=2;
' } else if(index==32){
' d[0]=3;
' d[1]=0;
' d[2]=0;
' d[3]=0;
' for(j=0;j<8;j++)d[1]|=(log[j]<<j);
' for(j=0;j<8;j++)d[2]|=(log[j+11]<<j);
' for(j=0;j<8;j++)d[3]|=(log[j+22]<<j);
' index=3;
' } else index=0; //invalid pulse string
' return index;
'}
'
Edited by matherp 2015-03-02
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6269
Posted: 11:42am 01 Mar 2015
Copy link to clipboard 
Print this post

  cosmic frog said   Is there a link to how the cfunction works or how to make your own cfunction as it just looks like a load of hex to me.
Thanks. Dave.


Cfunctions are described in the firmware download for the Micromite Mk2
http://geoffg.net/micromite.html

The ZIP includes some example code to get you started.

Jim
VK7JH
MMedit
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 12:08pm 01 Mar 2015
Copy link to clipboard 
Print this post

The CFunction Tutorial, 74 pages, is available from http://www.g8jcf.dyndns.org/mmbasicmkii/MMBasicCFunctions.pd f

Peter
The only Konstant is Change
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9588
Posted: 12:58pm 01 Mar 2015
Copy link to clipboard 
Print this post

  matherp said  Some people are just never satisfied


I did not mean to be a pain.

Being able to specify the pins to use for PS/2 is about as fullproof as you can get, cos then you are not tied to any set of pins - this is very flexable. In your examples, that will be how I am using it(pins 55 and 54 on the 470), as this leaves both COM ports free for my other purposes.

I am a high-mileage com-port user!

I certainly did not expect you to re-do the code to allow for this - I was just curious why you elected to use the COM2 pins, really, but this is a far better concept in MHO, cos now you can put the PS/2 keyboard on any pair of pins.


Smoke makes things work. When the smoke gets out, it stops!
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10209
Posted: 10:31pm 01 Mar 2015
Copy link to clipboard 
Print this post

  Quote  I was just curious why you elected to use the COM2 pins


I am a low-mileage com-port user!

On the MX470 you could you could "improve" the code as follows:


option explicit
option default none
'
const KBCLOCK=54
const KBDATA=55
'
setpin KBDATA,din ' KB clock
setpin KBCLOCK,din ' KB data
'
dim integer i
dim s$ length 3
do
i=ps2(s$, 1000, MM.SPEED\1000000, portnum(KBDATA), pinnum(KBDATA), portnum(KBCLOCK), pinnum(KBCLOCK)) 'String to receive KB data, timeout in msec, CPU speed in MHz, data port number, data pin number, clock port number, clock pin number
' In this example for the 64-pin MX470 the data pin definition is 3,7 (i.e. D07=pin 55) the clock pin definition is 3,6 (i.e D06=pin 54)
if i=0 then print "timeout"
if i=1 then print hex$(asc(left$(s$,1)))
if i=2 then print hex$(asc(left$(s$,1))), hex$(asc(mid$(s$,2,1)))
if i=3 then print hex$(asc(left$(s$,1))), hex$(asc(mid$(s$,2,1))), hex$(asc(right$(s$,1)))
loop
'
function portnum(ppin as integer)as integer
portnum=(portaddr(ppin)-&HBF886000)\&H100
end function
Edited by matherp 2015-03-03
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025