OpenCores
URL https://opencores.org/ocsvn/s6soc/s6soc/trunk

Subversion Repositories s6soc

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /s6soc/trunk
    from Rev 28 to Rev 29
    Reverse comparison

Rev 28 → Rev 29

/sw/zipos/cmodram.ld
58,7 → 58,7
obj-zip/keypad.o(.text)
obj-zip/display.o(.text)
obj-zip/rtcsim.o(.text)
*(.rodata) *(.strings)
*(.rodata*) *(.strings)
load_image_start = . ;
} > flash
.ramcode : {
/sw/zipos/doorbell.c
4,7 → 4,16
//
// Project: CMod S6 System on a Chip, ZipCPU demonstration project
//
// Purpose:
// Purpose: This is the user program, or perhaps more appropriately
// user program(s), associated with running the ZipOS on the
// CMod-S6. To run within the ZipOS, a user program must implement
// two functions: kntasks() and kinit(TASKP *). The first one is simple.
// it simply returns the number of tasks the kernel needs to allocate
// space for. The second routine needs to allocate space for each task,
// set up any file descriptors associated with (each) task, and identify
// the entry point of each task. These are the only two routines
// associated with user tasks called from kernel space. Examples of each
// are found within here.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
47,6 → 56,7
 
#include "../dev/display.h"
#include "../dev/rtcsim.h"
#include "../dev/keypad.h"
 
/* Our system will need some pipes to handle ... life. How about these:
*
58,9 → 68,8
* lcdpipe - write()s to this pipe write to the LCD display SPI port
* pwmpipe - write()s to this pipe will send values to the audio port
* Interrupt consumed
* cmdpipe - written to by the user command task, read by the display task
* used to communicate menu status
*
* These pipes are allocated within the kernel setup function, ksetup().
*/
 
/* We'll need some tasks as well:
108,6 → 117,15
*/
// #define KEYPAD_TASK keypad_task_id
/*
* Read from the keypad, and set up a series of menu screens on the Display,
* so that we can:
*
* 1. Set time
* 2. Set dawn
* 3. Set dusk
*/
#define MENU_TASK menu_task_id
/*
* Maintain a realtime clock
*/
#define RTCCLOCK_TASK rtccclock_task_id
122,12 → 140,6
*/
#define DOORBELL_TASK doorbell_task_id
 
/*
* Interract with any user commands, such as setting the clock, setting
* nighttime (when the lights turn on) or setting daytime when only the
* doorbell rings.
*/
// #define COMMAND_TASK command_task_id
#define LAST_TASK last_task_id
 
typedef enum {
139,8 → 151,11
DOORBELL_TASK, DISPLAY_TASK,
#endif
#endif
#ifdef KEYPAD_TASK
KEYPAD_TASK,
//#ifdef KEYPAD_TASK
//KEYPAD_TASK,
//#endif
#ifdef MENU_TASK
MENU_TASK,
#endif
#ifdef COMMAND_TASK
COMMAND_TASK,
153,7 → 168,7
doorbell_task(void),
display_task(void),
keypad_task(void),
command_task(void);
menu_task(void);
// idle_task ... is accomplished within the kernel
extern void restore_context(int *), save_context(int *);
extern SYSPIPE *rxpipe, *txpipe, *pwmpipe, *lcdpipe;
171,43 → 186,42
#ifdef DOORBELL_TASK
#ifdef DISPLAY_TASK
// 13 + 10 +9(uwrite)+4(uarthex)+2(uartstr)+2(uartchr)
tasklist[DOORBELL_TASK] = new_task(64, doorbell_task);
tasklist[DOORBELL_TASK]->fd[FILENO_STDOUT] = sys_malloc(sizeof(KFILDES));
tasklist[DOORBELL_TASK]->fd[FILENO_STDOUT]->id = (int)lcdpipe;
tasklist[DOORBELL_TASK]->fd[FILENO_STDOUT]->dev= pipedev;
tasklist[DOORBELL_TASK]->fd[FILENO_STDERR] = sys_malloc(sizeof(KFILDES));
tasklist[DOORBELL_TASK]->fd[FILENO_STDERR]->id = (int)txpipe;
tasklist[DOORBELL_TASK]->fd[FILENO_STDERR]->dev= pipedev;
tasklist[DOORBELL_TASK]->fd[FILENO_AUX] = sys_malloc(sizeof(KFILDES));
tasklist[DOORBELL_TASK]->fd[FILENO_AUX]->id = (int)pwmpipe;
tasklist[DOORBELL_TASK]->fd[FILENO_AUX]->dev= pipedev;
tasklist[DOORBELL_TASK] = new_task(96, doorbell_task);
// tasklist[DOORBELL_TASK]->fd[FILENO_STDOUT]= kopen((int)lcdpipe,pipedev);
tasklist[DOORBELL_TASK]->fd[FILENO_STDERR]= kopen((int)txpipe, pipedev);
tasklist[DOORBELL_TASK]->fd[FILENO_AUX] = kopen((int)pwmpipe, pipedev);
 
//
tasklist[DISPLAY_TASK] = new_task(32, display_task);
tasklist[DISPLAY_TASK]->fd[FILENO_STDIN] = sys_malloc(sizeof(KFILDES));
tasklist[DISPLAY_TASK]->fd[FILENO_STDIN]->id = (int)lcdpipe;
tasklist[DISPLAY_TASK]->fd[FILENO_STDIN]->dev= pipedev;
tasklist[DISPLAY_TASK]->fd[FILENO_STDIN] = kopen((int)lcdpipe,pipedev);
#endif
#endif
 
 
#ifdef KEYPAD_TASK
tasklist[KEYPAD_TASK] = new_task(16, keypad_task);
tasklist[KEYPAD_TASK]->fd[FILENO_STDOUT] = sys_malloc(sizeof(KFILDES));
tasklist[NMEA_TASK]->fd[FILENO_STDOUT]->id = (int)keypipe;
tasklist[NMEA_TASK]->fd[FILENO_STDOUT]->dev= pipedev;
// Stack = 7 + 9(uwrite) + 2*4
tasklist[KEYPAD_TASK] = new_task(32, keypad_task);
tasklist[KEYPAD_TASK]->fd[FILENO_STDOUT] = kopen((int)keypipe,pipedev);
#endif
#ifdef MENU_TASK
// Stack = 18 + 10(showbell/shownow) + 9(uwrite) + 2(menu_readkey)
// + 18 (time_menu/dawn_menu/dusk_menu)
tasklist[MENU_TASK] = new_task(72, menu_task);
// tasklist[MENU_TASK]->fd[FILENO_STDIN] = kopen((int)keypipe,pipedev);
tasklist[MENU_TASK]->fd[FILENO_STDOUT]= kopen((int)lcdpipe,pipedev);
tasklist[MENU_TASK]->fd[FILENO_STDERR]= kopen((int)txpipe, pipedev);
#endif
}
 
#ifdef DOORBELL_TASK
// #define HALF_HOUR_S 1800 // Seconds per half hour
// #define HALF_HOUR_S 180 // Seconds per three minutes--for test
#define HALF_HOUR_S 30 // 3 Mins is to long, here's 3 seconds
 
#include "../dev/samples.c"
 
#ifdef MENU_TASK
unsigned dawn = 0x060000, dusk = 0x180000;
#else
const unsigned dawn = 0x060000, dusk = 0x180000;
int nwritten = 0, nread = 0, nstarts = 0;
#endif
 
void shownow(unsigned now) { // Uses 10 stack slots + 8 for write()
char dmsg[9];
252,14 → 266,6
write(FILENO_STDOUT, dmsg, 9);
}
 
void belllight(unsigned now) {
IOSPACE *sys = (IOSPACE *)IOADDR;
if ((now < dawn)||(now > dusk))
sys->io_spio = 0x088; // Turn our light on
else
sys->io_spio = 0x80; // Turn light off
}
 
void uartchr(char v) {
if (write(FILENO_STDERR, &v, 1) != 1)
write(FILENO_STDERR, "APPLE-PANIC", 11);
282,9 → 288,20
else
ch += '0';
uartchr(ch);
} uartstr("\r\n\0");
} uartstr("\r\n");
}
 
#ifdef DOORBELL_TASK
#include "../dev/samples.c"
 
void belllight(unsigned now) {
IOSPACE *sys = (IOSPACE *)IOADDR;
if ((now < dawn)||(now > dusk))
sys->io_spio = 0x088; // Turn our light on
else
sys->io_spio = 0x80; // Turn light off
}
 
void doorbell_task(void) {
// Controls LED 0x08
 
293,21 → 310,25
// write(KFD_STDOUT, disp_build_gtlogo, sizeof(disp_build_gtlogo));
// write(KFD_STDOUT, disp_reset_data, sizeof(disp_reset_data));
// write(KFD_STDOUT, disp_gtech_data, sizeof(disp_gtech_data));
 
IOSPACE *sys = (IOSPACE *)IOADDR;
 
while(1) {
nread = nwritten = 0;
int event;
// Initial state: doorbell is not ringing. In this state, we
// can wait forever for an event
sys->io_spio = 0x080; // Turn our light off
event = wait(INT_BUTTON|SWINT_PPS,-1);
 
#ifndef MENU_TASK
unsigned when = rtcclock;
if (event & INT_BUTTON)
showbell(when);
else if (event & SWINT_PPS)
shownow(when);
#else
if (event & INT_BUTTON)
post(SWINT_DOORBELL);
#endif
 
while(event & INT_BUTTON) {
// Next state, the button has been pressed, the
326,17 → 347,9
if (len > 256)
len = 256;
 
/*
while(len > 64) {
write(FILENO_AUX, sptr, 64);
sptr += 64;
len -= 64;
}*/
 
// We will stall here, if the audio FIFO is full
write(FILENO_AUX, sptr, len);
sptr += len;
nwritten += len;
 
// If the user presses the button more than
// once, we start the sound over as well as
343,21 → 356,25
// our light counter.
event = wait(INT_BUTTON|SWINT_PPS, 0);
if (event&INT_BUTTON) {
if (sptr > &sound_data[2048]) {
if (sptr > &sound_data[1024]) {
sptr = sound_data;
seconds = 0;
#ifndef MENU_TASK
when = (volatile unsigned)rtcclock;
showbell(when);
#else
post(SWINT_DOORBELL);
#endif
}
} else if (event&SWINT_PPS) {
seconds++;
belllight(rtcclock);
#ifndef MENU_TASK
showbell(when);
#endif
}
}
 
uartchr('D');
// Next state: the doorbell is no longer ringing, but
// we have yet to return to normal--the light is still
// on.
365,32 → 382,279
(((event=wait(INT_BUTTON|SWINT_PPS,-1))&INT_BUTTON)==0)) {
seconds++;
belllight(rtcclock);
#ifndef MENU_TASK
showbell(when);
#endif
}
if (event&INT_BUTTON) {
#ifndef MENU_TASK
when = (volatile unsigned)rtcclock;
showbell(when);
uartchr('B');
#endif
}
}
 
// uartstr("\r\n");
uartstr("\r\nNWritten: "); uarthex(nwritten);
uartstr("NRead : "); uarthex(nread);
uartstr("NStarts : "); uarthex(nstarts);
nwritten = nread = nstarts = 0;
}
}
#endif
 
#ifdef MENU_TASK
void entered_menu_str(char *str, unsigned now,int pos) {
//
// Set current time
// xx:xx:xx
//
str[0] = PACK(0x1b, '[', '1',';');
str[1] = PACK('0','H',' ',' ');
str[2] = PACK(' ','x','x',':');
str[3] = PACK('x','x',' ',' ');
//str[3]=PACK('x','x',':','x');
str[4] = PACK(' ','\0','\0','\0');
 
if (pos>0) {
int ch = ((now >> 20)&0x0f)+'0';
str[2] &= ~0x0ff0000;
str[2] |= (ch<<16);
 
/*
if (pos > 1) {
int ch = ((now >> 16)&0x0f)+'0';
str[2] &= ~0x0ff00;
str[2] |= (ch<<8);
 
if (pos > 2) {
int ch = ((now >> 12)&0x0f)+'0';
str[3] &= ~0xff000000;
str[3] |= (ch<<24);
 
NWritten: 000018E7
NRead : 000018E7
NStarts : 00000001
if (pos > 3) {
int ch = ((now >> 8)&0x0f)+'0';
str[3] &= ~0x0ff0000;
str[3] |= (ch<<16);
 
if (pos > 4) {
int ch = ((now >> 4)&0x0f)+'0';
str[3] &= ~0x0ff00;
str[3] |= ':'<<8;
str[3] &= ~0x0ff;
str[3] |= (ch);
 
*/
if (pos > 5)
ch = (now&0x0f)+'0';
else
ch = 'x';
str[4] &= ~0x0ff000000;
str[4] |= (ch<<24);
}}}}}
}
 
void show_time_menu(unsigned when, int posn) {
char dmsg[10];
dmsg[0] = PACK(0x1b,'[','j','S');
dmsg[1] = PACK('e','t',' ','c');
dmsg[2] = PACK('u','r','r','e');
dmsg[3] = PACK('n','t',' ','t');
dmsg[4] = PACK('i','m','e',':');
entered_menu_str(&dmsg[5], when, posn);
write(FILENO_STDOUT, dmsg, 9);
}
 
void show_dawn_menu(unsigned when, int posn) {
char dmsg[10];
dmsg[0] = PACK(0x1b,'[','j','S');
dmsg[1] = PACK('e','t',' ','s');
dmsg[2] = PACK('u','n','r','i');
dmsg[3] = PACK('s','e',':','\0');
entered_menu_str(&dmsg[4], when, posn);
write(FILENO_STDOUT, dmsg, 8);
}
 
void show_dusk_menu(unsigned when, int posn) {
char dmsg[10];
dmsg[0] = PACK(0x1b,'[','j','S');
dmsg[1] = PACK('e','t',' ','s');
dmsg[2] = PACK('u','n','s','e');
dmsg[3] = PACK('t',':','\0','\0');
entered_menu_str(&dmsg[4], when, posn);
write(FILENO_STDOUT, dmsg, 8);
}
 
int menu_readkey(void) {
int key;
wait(0,3);
key = keypadread();
keypad_wait_for_release();
clear(INT_KEYPAD);
return key;
}
 
void time_menu(void) {
int timeout = 60;
unsigned newclock = 0;
for(int p=0; p<6; p++) {
int key, event;
show_time_menu(newclock, p);
do {
event = wait(SWINT_PPS|INT_KEYPAD,-1);
if (event&SWINT_PPS) {
timeout--;
if (timeout == 0)
return;
} if (event&INT_KEYPAD) {
timeout = 60;
key = menu_readkey();
if ((key >= 0)&&(key < 10)) {
int sh;
sh = (5-p)*4;
newclock &= ~(0x0f<<sh);
newclock |= (key<<sh);
} else if (key == 12) {
if (p>=0)
p--;
} else {
if (p > 4)
break;
else
return;
}
}
} while(0==(event&INT_KEYPAD));
}
 
clear(SWINT_PPS);
rtcclock = newclock;
if (wait(SWINT_PPS, 1))
rtcclock = newclock;
}
 
void dawn_menu(void) {
int timeout = 60;
unsigned newdawn = 0;
for(int p=0; p<6; p++) {
int key, event;
show_dawn_menu(newdawn, p);
do {
event = wait(SWINT_PPS|INT_KEYPAD,-1);
if (event&SWINT_PPS) {
timeout--;
if (timeout == 0)
return;
} if (event&INT_KEYPAD) {
timeout = 60;
key = menu_readkey();
if ((key >= 0)&&(key < 10)) {
int sh = (5-p)*4;
newdawn &= ~(0x0f<<sh);
newdawn |= key<<sh;
} else if (key == 12) {
if (p>=0)
p--;
} else {
if (p > 4)
break;
else
return;
}
}
} while(0 == (event&INT_KEYPAD));
} dawn = newdawn;
}
 
void dusk_menu(void) {
int timeout = 60;
unsigned newdusk = 0;
for(int p=0; p<6; p++) {
int key, event;
show_dusk_menu(newdusk, p);
do {
event = wait(SWINT_PPS|INT_KEYPAD,-1);
if (event&SWINT_PPS) {
timeout--;
if (timeout == 0)
return;
} if (event&INT_KEYPAD) {
key = menu_readkey();
if ((key >= 0)&&(key < 10)) {
int sh = (5-p)*4;
newdusk &= ~(0x0f<<sh);
newdusk |= key<<sh;
} else if (key == 12) {
if (p>=0)
p--;
} else {
if (p > 4)
break;
else
return;
}
}
} while(0 == (event&INT_KEYPAD));
} dusk = newdusk;
}
 
void unknown_menu(void) {
// 0123456789ABCDEF
// Unknown Cmd Key
// A/Tm B/Dwn C/Dsk
char dmsg[11];
dmsg[0] = PACK(0x1b,'[','j','U');
dmsg[1] = PACK('n','k','n','o');
dmsg[2] = PACK('w','n',' ','C');
dmsg[3] = PACK('m','d',' ','K');
dmsg[4] = PACK('e','y','\0','\0');
dmsg[5] = PACK(0x1b,'[','1',';');
dmsg[6] = PACK('0','H','A','/');
dmsg[7] = PACK('T','m',' ','B');
dmsg[8] = PACK('/','D','w','n');
dmsg[9] = PACK(' ','C','/','D');
dmsg[10] = PACK('s','k',0,0);
write(FILENO_STDOUT, dmsg, 11);
}
void menu_task(void) {
// Controls LED 0x08
 
// Start by initializing the display to GT Gisselquist\nTechnology
// write(KFD_STDOUT, disp_build_backslash,sizeof(disp_build_backslash));
// write(KFD_STDOUT, disp_build_gtlogo, sizeof(disp_build_gtlogo));
// write(KFD_STDOUT, disp_reset_data, sizeof(disp_reset_data));
// write(KFD_STDOUT, disp_gtech_data, sizeof(disp_gtech_data));
IOSPACE *sys = (IOSPACE *)IOADDR;
unsigned belltime = 0, when;
 
 
when = rtcclock;
while(1) {
int event;
// Initial state: doorbell is not ringing. In this state, we
// can wait forever for an event
sys->io_spio = 0x080; // Turn our light off
event = wait(SWINT_DOORBELL|SWINT_PPS|INT_KEYPAD,-1);
if (event & SWINT_DOORBELL) {
showbell(when);
belltime = time();
} else if (event & SWINT_PPS) {
unsigned now = time();
if ((now-belltime)<HALF_HOUR_S)
showbell(when);
else {
when = rtcclock;
shownow(when);
}
}
 
if (event & INT_KEYPAD) {
int key;
key = menu_readkey();
switch(key) {
case 10: time_menu();
when = rtcclock;
break;
case 11: dawn_menu(); break;
case 12: dusk_menu(); break;
default:
unknown_menu();
wait(0,3000);
} clear(INT_KEYPAD);
}
}
}
#endif
 
/sw/zipos/swint.h
50,5 → 50,6
#define SWINT_PPD 0x020000
#define SWINT_ALARM 0x040000
#define SWINT_CLOCK 0x080000
#define SWINT_DOORBELL 0x100000
 
#endif
/sw/zipos/ksetup.c
6,7 → 6,7
//
// Purpose: These are the routines from kernel.c that didn't need to be
// in RAM memory. They are specifically the pre-run setup
// routines.
// routines that are executed from FLASH memory.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
58,6 → 58,7
 
int LAST_TASK;
 
__attribute__((cold))
TASKP *ksetup(void) {
TASKP *tasklist;
IOSPACE *sys = (IOSPACE *)IOADDR;
78,7 → 79,7
txpipe = new_syspipe(8); txpipe->m_rdtask = INTERRUPT_READ_TASK;
keypipe = new_syspipe(16);
lcdpipe = new_syspipe(16);
pwmpipe = new_syspipe(256); pwmpipe->m_rdtask= INTERRUPT_READ_TASK;
pwmpipe = new_syspipe(128); pwmpipe->m_rdtask= INTERRUPT_READ_TASK;
cmdpipe = new_syspipe(16);
 
tasklist = sys_malloc(sizeof(TASKP)*(1+LAST_TASK));
112,12 → 113,14
sys->io_spio = 0x0f7;
}
 
// __attribute__((noreturn))
void kuserexit(int a) {
syscall(TRAPID_EXIT, a, 0, 0);
}
 
__attribute__((malloc))
void *sys_malloc(int sz) {
{
if (0) {
SCOPE *s = (SCOPE *)SCOPEADDR;
s->s_control = TRIGGER_SCOPE_NOW | (s->s_control & 0x0ffff);
}
132,3 → 135,9
return res;
}
 
KFILDES *kopen(int id, KDEVICE *dev) {
KFILDES *fd = (KFILDES *)sys_malloc(sizeof(KFILDES));
fd->id = (int)id;
fd->dev= dev;
return fd;
}
/sw/zipos/kernel.c
72,8 → 72,6
 
int LAST_TASK;
 
extern int nwritten, nread, nstarts;
 
void kernel_entry(void) {
int nheartbeats= 0, tickcount = 0, milliseconds=0, ticks = 0;
int audiostate = 0, buttonstate = 0;
183,7 → 181,6
} else if (kpop_syspipe(pwmpipe, &v)==0) {
audiostate = (2|(v<<2))&0x03ffff;
sys->io_pwm_audio = (v>>16)&0x0ffff;
nread++;
} else {
audiostate = 0;
// Turn the device off
203,8 → 200,6
}} else { // if (audiostate == 0)
int sample;
if (kpop_syspipe(pwmpipe, &sample)==0) {
nstarts++;
nread++;
audiostate = (2|(sample<<2))&0x03ffff;
sys->io_pwm_audio = 0x310000 | ((sample>>16)&0x0ffff);
enableset |= (INT_ENABLEV(INT_AUDIO));
211,7 → 206,8
sys->io_spio = 0x022;
sys->io_pic = INT_AUDIO;
} // else sys->io_spio = 0x020;
} milliseconds = kpost(tasklist, pic, milliseconds);
}
milliseconds = kpost(tasklist, pic, milliseconds);
 
// Restart interrupts
enableset &= (~0x0ffff); // Keep the bottom bits off
229,8 → 225,6
sys->io_pic = INT_AUDIO;
enableset |= (INT_ENABLEV(INT_AUDIO));
sys->io_spio = 0x022;
nstarts++;
nread++;
} // else sys->io_spio = 0x020;
 
// Or the beginning of a transmit pipe.
326,10 → 320,11
else { kpanic(); zip_halt(); }
if ((!fd)||(!fd->dev))
last_context[1] = -EBADF;
else
else {
fd->dev->write(current, fd->id,
(void *)last_context[3], last_context[4]);
} break;
}}
break;
case TRAPID_TIME:
last_context[1] = tickcount;
break;
392,11 → 387,12
}
 
// Now let's see if we can find the next ready task to run
for(; nxtid<LAST_TASK; nxtid++)
for(; nxtid<LAST_TASK; nxtid++) {
if (tasklist[nxtid]->state == SCHED_READY) {
current=tasklist[nxtid];
break;
}
}
// The last task (the idle task) doesn't count
if (nxtid >= LAST_TASK) {
nxtid = 0; // Don't automatically run idle task
406,8 → 402,7
}
// Now we stop at the idle task, if nothing else is ready
current = tasklist[nxtid];
}
return current;
} return current;
}
 
int kpost(TASKP *tasklist, unsigned events, int milliseconds) {
/sw/zipos/kfildes.h
68,4 → 68,6
#define NULL (void *)0
#endif
 
KFILDES *kopen(int id, KDEVICE *dev);
 
#endif
/sw/zipos/Makefile
73,6 → 73,9
$(OBJDIR)/%.s: %.c
$(CC) -S $(CFLAGS) -c $< -o $@
 
$(OBJDIR)/%.s: ../dev/%.c
$(CC) -S $(CFLAGS) -c $< -o $@
 
$(OBJDIR)/resetdump.o: resetdump.s
$(AS) $^ -o $@
 
/sw/dev/keypad.h
0,0 → 1,46
////////////////////////////////////////////////////////////////////////////////
//
// Filename: keypad.h
//
// Project: CMod S6 System on a Chip, ZipCPU demonstration project
//
// Purpose: A device driver (task) for the 16 character keypad.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#ifndef KEYPAD_H
#define KEYPAD_H
extern int keypadread(void);
extern void keypad_wait_for_release(void);
 
#ifdef ZIPOS
extern void keypad_task(void);
#endif
#endif
/sw/dev/kptest.c
0,0 → 1,93
////////////////////////////////////////////////////////////////////////////////
//
// Filename: kptest.c
//
// Project: CMod S6 System on a Chip, ZipCPU demonstration project
//
// Purpose: To test and demonstrate that the keypad works.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#include "asmstartup.h"
#include "board.h"
#include "keypad.h"
 
void txchr(char v) {
volatile IOSPACE *sys = (IOSPACE *)IOADDR;
if (v < 10)
return;
v &= 0x07f;
sys->io_pic = INT_UARTTX;
while((sys->io_pic&INT_UARTTX)==0)
;
sys->io_uart = v;
}
 
void txstr(const char *str) {
const char *ptr = str;
while(*ptr) {
txchr(*ptr++);
}
}
 
void entry(void) {
register IOSPACE *sys = (IOSPACE *)0x0100;
 
sys->io_pic = 0x07fffffff; // Acknowledge and turn off all interrupts
sys->io_spio = 0x0f0;
sys->io_tima = 100000 | TM_REPEAT;
 
txstr("Press any keypad button for test.\r\n");
 
while(1) {
int ch;
while(0 == (sys->io_pic & INT_KEYPAD))
;
sys->io_pic = INT_KEYPAD | INT_TIMA;
// Wait 5 ms
for(int i=0; i<5; i++) {
while(0 == (sys->io_pic & INT_TIMA))
;
}
sys->io_spio = 0x011;
ch = keypadread();
if (ch < 0)
; // txstr("Unknown key pressed or error\n");
else if (ch < 10)
txchr(ch+'0');
else if (ch == 15)
txstr("F\r\n");
else if (ch < 15)
txchr(ch+'A'-10);
else txstr("Unknown key pressed\n");
keypad_wait_for_release();
sys->io_spio = 0x010;
}
}
/sw/dev/Makefile
46,7 → 46,7
##
##
all:
PROGRAMS := helloworld
PROGRAMS := helloworld doorbell doorbell2 kptest
all: $(OBJDIR)/ $(PROGRAMS)
 
 
61,7 → 61,7
# Not for build, for for building tags and dependency files, we need to know
# what the sources and headers are
DEVDRVR:= keypad.c display.c rtcsim.c
SOURCES:= helloworld.c doorbell.c doorbell2.c $(DEVDRVR)
SOURCES:= helloworld.c doorbell.c doorbell2.c kptest.c $(DEVDRVR)
HEADERS:= board.h
# OBJECTS:= $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(SOURCES)))
OBJDRVR := $(addprefix $(OBJDIR)/,$(subst .c,.o,$(DEVDRVR)))
96,6 → 96,11
$(OBJDIR)/doorbell2.txt: doorbell2
$(OBJDUMP) -dr $^ > $@
 
kptest: $(OBJDIR)/ $(OBJDIR)/kptest.o $(OBJDRVR) cmod.ld
$(CC) $(LDFLAGS) $(OBJDIR)/kptest.o $(OBJDRVR) -o $@
$(OBJDIR)/kptest.txt: kptest
$(OBJDUMP) -dr $^ > $@
 
define build-depends
@echo "Building dependency file(s)"
$(CC) $(CPPFLAGS) -MM $(SOURCES) > $(OBJDIR)/xdep.txt
/sw/dev/keypad.c
0,0 → 1,138
////////////////////////////////////////////////////////////////////////////////
//
// Filename: keypad.c
//
// Project: CMod S6 System on a Chip, ZipCPU demonstration project
//
// Purpose: A device driver (task) for the 16 character keypad.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#include "board.h"
#ifdef ZIPOS
#include "../zipos/ktraps.h"
#include "../zipos/kfildes.h"
#endif
 
static const int keymap[] = {
0x01,0x02,0x03,0x0a,
0x04,0x05,0x06,0x0b,
0x07,0x08,0x09,0x0c,
0x00,0x0f,0x0e,0x0d
};
 
int keypadread(void) {
int row, col, key;
IOSPACE *sys = (IOSPACE *)IOADDR;
 
row = sys->io_spio & 0x0f00;
if (row != 0x0f00) {
// If a button is still pressed ..
//
// Check columns one and two to see if they were responsible
// for the button
sys->io_spio = 0x0cf00;
// Get the result
col = sys->io_spio;
if ((col&0x0f00)!=0x0f00) {
// Column one or two is pressed
sys->io_spio = 0x0ef00;
col = sys->io_spio;
if ((col&0x0f00)!=0x0f00)
col = 0;
else
col = 1;
} else {
// Must be column three or four
sys->io_spio = 0x7f00;
col = sys->io_spio;
if ((col & 0x0f00)!= 0x0f00) // Column 4
col = 3;
else
col = 2;
} sys->io_spio = 0x0f00; // Reset column pins to zero
if (row == (int)(sys->io_spio & 0x0f00)) {
// The key didn't change, so we might have something
row >>= 8;
row &= 0x0f;
row ^= 0x0f;
// Found the pin
if (row == 1)
row=0;
else if (row == 2)
row = 1;
else if (row == 4)
row = 2;
else if (row == 8)
row = 3;
else
// Two or more buttons were pressed
// -- declare an error
row = -1;
 
if (row>=0) {
key = (row |(col<<2));
key = keymap[key];
} else key = -1;
} else key = -1;
} else key = -1;
 
if (sys->io_pic & INT_ENABLE)
sys->io_pic = INT_ENABLE|INT_KEYPAD;
else sys->io_pic = INT_KEYPAD;
 
return key;
}
 
void keypad_wait_for_release(void) {
IOSPACE *sys = (IOSPACE *)IOADDR;
sys->io_spio = 0x0f00;
while((sys->io_spio & 0x0f00)!=0x0f00)
#ifdef ZIPOS
wait(0,2);
#else
;
#endif
}
 
#ifdef ZIPOS
void keypad_task(void) {
clear(INT_KEYPAD);
while(1) {
int key;
wait(INT_KEYPAD,-1); // Automatically clears
key = keypadread();
write(FILENO_STDOUT, &key, 1);
// Prepare for the next key
clear(INT_KEYPAD);
}
}
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.