Line 2... |
Line 2... |
//
|
//
|
// Filename: doorbell2.c
|
// Filename: doorbell2.c
|
//
|
//
|
// Project: CMod S6 System on a Chip, ZipCPU demonstration project
|
// Project: CMod S6 System on a Chip, ZipCPU demonstration project
|
//
|
//
|
// Purpose: A modification to the original doorbell.c program.
|
// Purpose: A modification to the original doorbell.c program that played
|
// seconds. Listening to that test is ... getting old.
|
// a doorbell sound every ten seconds. Listening to that test is
|
|
// ... getting old.
|
//
|
//
|
// Let's let this one do the following:
|
// Let's let this one do the following:
|
// 1. Display the time on the display (it will be impossible to
|
// 1. Display the time on the display (it will be impossible to
|
// change the time, sadly, but we can at least display it.)
|
// change the time, sadly, but we can at least display it.)
|
// 2. On button press ...
|
// 2. On button press ...
|
Line 23... |
Line 24... |
// Creator: Dan Gisselquist, Ph.D.
|
// Creator: Dan Gisselquist, Ph.D.
|
// Gisselquist Technology, LLC
|
// Gisselquist Technology, LLC
|
//
|
//
|
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
|
// Copyright (C) 2015-2017, Gisselquist Technology, LLC
|
//
|
//
|
// This program is free software (firmware): you can redistribute it and/or
|
// 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
|
// 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
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
// your option) any later version.
|
// your option) any later version.
|
Line 51... |
Line 52... |
//
|
//
|
#include "asmstartup.h"
|
#include "asmstartup.h"
|
#include "board.h"
|
#include "board.h"
|
#include "rtcsim.h"
|
#include "rtcsim.h"
|
#include "display.h"
|
#include "display.h"
|
|
#include "string.h"
|
|
#include "txfns.h"
|
|
|
#include "samples.c"
|
#include "samples.c"
|
|
|
void zip_halt(void);
|
void zip_halt(void);
|
|
|
void build_dpymsg(char *msg, unsigned clkval);
|
void build_dpymsg(char *msg, unsigned clkval);
|
void build_uartmsg(char *msg, unsigned clkval);
|
void build_uartmsg(char *msg, unsigned clkval);
|
void showval(int val);
|
void showval(int val);
|
void txval(int val);
|
|
|
#define CLEAR_WATCHDOG _sys->io_watchdog = 0
|
|
#define TOUCH_WATCHDOG _sys->io_watchdog = 500000
|
|
|
void entry(void) {
|
void entry(void) {
|
register IOSPACE *sys = (IOSPACE *)0x0100;
|
register volatile IOSPACE *const sys = _sys;
|
char dpymsg[16], *dpyptr;
|
char dpymsg[64], *dpyptr;
|
char uartmsg[40], *uartptr;
|
char uartmsg[160], *uartptr;
|
int newmsgtime = 0, leastmsgtime = -1, lstmsgtime = 0;
|
int newmsgtime = 0, leastmsgtime = -1, lstmsgtime = 0;
|
|
|
|
CLEAR_WATCHDOG;
|
|
|
|
txstr("\r\nREBOOT!\r\n");
|
|
txstr("Scope Control = "); txval(_scope->s_ctrl);
|
|
if (_scope->s_ctrl & WBSCOPE_STOPPED) {
|
|
int ln = WBSCOPE_LENGTH(_scope->s_ctrl);
|
|
for(int i=0; i<ln; i++)
|
|
txval(_scope->s_data);
|
|
txval((int)_sys->io_buserr);
|
|
txstr("\r\n\r\nEndScope\r\n");
|
|
} else {
|
|
txstr("\r\n");
|
|
_scope->s_ctrl = 20;
|
|
}
|
|
|
dpymsg[0] = 0;
|
dpymsg[0] = 0;
|
dpyptr = dpymsg;
|
dpyptr = dpymsg;
|
|
|
uartmsg[0] = 0;
|
uartmsg[0] = 0;
|
build_uartmsg(uartmsg, 0);
|
build_uartmsg(uartmsg, 0);
|
uartptr = uartmsg;
|
uartptr = uartmsg;
|
|
|
sys->io_timb = 0;
|
sys->io_watchdog = 0;
|
sys->io_pic = 0x07fffffff; // Acknowledge and turn off all interrupts
|
sys->io_pic = INT_CLEARPIC; // Acknowledge and turn off all interrupts
|
|
|
sys->io_spio = 0x0f4;
|
sys->io_spio = 0x0f4;
|
newmsgtime = sys->io_tima;
|
newmsgtime = sys->io_timer;
|
leastmsgtime = -1;
|
leastmsgtime = -1;
|
lstmsgtime = newmsgtime;
|
lstmsgtime = newmsgtime;
|
while(1) {
|
while(1) {
|
int seconds, pic;
|
int seconds, pic;
|
const int *sptr;
|
const short *sptr;
|
|
|
// LED's off ... nothing to report
|
// LED's off ... nothing to report
|
sys->io_spio = 0x0f0;
|
sys->io_spio = 0x0f0;
|
|
|
// Turn the audio off (initially)
|
// Turn the audio off (initially)
|
sys->io_pwm_audio = 0x0018000;
|
sys->io_pwm_audio = 0x0018000;
|
|
|
// Set for one ticks per second, 80M clocks per tick
|
// Set for one ticks per second, 80M clocks per tick
|
sys->io_tima = TM_ONE_SECOND | TM_REPEAT;
|
sys->io_timer = TM_ONE_SECOND | TM_REPEAT;
|
|
|
// We start by waiting for a doorbell
|
// We start by waiting for a doorbell
|
while(((pic=sys->io_pic) & INT_BUTTON)==0) {
|
while(((pic=sys->io_pic) & INT_BUTTON)==0) {
|
if (uartmsg[10] == 0) {
|
TOUCH_WATCHDOG;
|
sys->io_spio = 0x0fe;
|
|
zip_halt();
|
if (pic & INT_TIMER) {// top of second
|
}
|
sys->io_pic = INT_TIMER;
|
if (pic & INT_TIMA) {// top of second
|
|
sys->io_pic = INT_TIMA;
|
|
rtcclock = rtcnext(rtcclock);
|
rtcclock = rtcnext(rtcclock);
|
|
|
// Turn all LED off (again)
|
// Turn all LED off (again)
|
sys->io_spio = 0x0f0;
|
sys->io_spio = 0x0f0;
|
if (*dpyptr == '\0') {
|
if (*dpyptr == '\0') {
|
Line 116... |
Line 134... |
build_uartmsg(uartmsg, rtcclock);
|
build_uartmsg(uartmsg, rtcclock);
|
uartptr = uartmsg;
|
uartptr = uartmsg;
|
|
|
// Turn one LED on--top of minute
|
// Turn one LED on--top of minute
|
sys->io_spio = 0x0f1;
|
sys->io_spio = 0x0f1;
|
newmsgtime = sys->io_tima;
|
newmsgtime = sys->io_timer;
|
lstmsgtime = -1;
|
lstmsgtime = -1;
|
leastmsgtime = -1;
|
leastmsgtime = -1;
|
}
|
}
|
}
|
}
|
/*
|
|
if (uartmsg[10] == 0) {
|
|
sys->io_spio = 0x0fc;
|
|
zip_halt();
|
|
}
|
|
*/
|
|
if (*uartptr) {
|
if (*uartptr) {
|
if (pic & INT_UARTTX) {
|
if (pic & INT_UARTTX) {
|
sys->io_uart = *uartptr++;
|
sys->io_uart = *uartptr++;
|
sys->io_spio = 0x22;
|
sys->io_spio = 0x22;
|
sys->io_pic = INT_UARTTX;
|
sys->io_pic = INT_UARTTX;
|
if (uartptr > &uartmsg[13]) {
|
|
sys->io_spio = 0x0fd;
|
|
zip_halt();
|
|
}
|
|
|
|
if (lstmsgtime != -1) {
|
if (lstmsgtime != -1) {
|
int tmp;
|
int tmp;
|
tmp = (lstmsgtime-sys->io_tima);
|
tmp = (lstmsgtime-sys->io_timer);
|
if ((leastmsgtime<0)||(tmp<leastmsgtime))
|
if ((leastmsgtime<0)||(tmp<leastmsgtime))
|
leastmsgtime = tmp;
|
leastmsgtime = tmp;
|
} lstmsgtime = sys->io_tima;
|
} lstmsgtime = sys->io_timer;
|
}
|
}
|
} else {
|
} else {
|
sys->io_spio = 0x20;
|
sys->io_spio = 0x20;
|
/*
|
|
if (newmsgtime != 0) {
|
|
int thistime = sys->io_tima;
|
|
thistime = newmsgtime - thistime;
|
|
showval(thistime);
|
|
txval(thistime);
|
|
txval(leastmsgtime);
|
|
txval(lstmsgtime);
|
|
zip_halt();
|
|
newmsgtime = 0;
|
|
}
|
|
for(int i=0; i<12; i++)
|
|
if (uartmsg[i] == 0) {
|
|
sys->io_spio = i+0xf0;
|
|
zip_halt();
|
|
}
|
|
*/
|
|
}
|
}
|
if (*dpyptr) {
|
if (*dpyptr) {
|
// This will take a long time. It should be an
|
// This will take a long time. It should be an
|
// interruptable task ... but, sigh, we're not
|
// interruptable task ... but, sigh, we're not
|
// there yet.
|
// there yet.
|
dispchar(*dpyptr++);
|
dispchar(*dpyptr++);
|
sys->io_spio = 0x44;
|
sys->io_spio = 0x44;
|
} else {
|
} else {
|
sys->io_spio = 0x40;
|
sys->io_spio = 0x40;
|
} // sys->io_pic = (pic & (INT_TIMA|INT_UARTTX));
|
} // sys->io_pic = (pic & (INT_TIMER|INT_UARTTX));
|
}
|
}
|
|
|
|
TOUCH_WATCHDOG;
|
// DOORBELL!!!!!!
|
// DOORBELL!!!!!!
|
// Set the Display message
|
// Set the Display message
|
dpymsg[0] = (0x1b<<24)|('['<<16)|('j'<<8)|'D';
|
strcpy(dpymsg, "a[jDoorbell!");
|
dpymsg[1] = ('o'<<24)|('o'<<16)|('r'<<8)|'b';
|
dpymsg[0] = 0x1b;
|
dpymsg[2] = ('e'<<24)|('l'<<16)|('l'<<8)|'!';
|
|
dpymsg[3] = 0;
|
|
dpyptr = dpymsg;
|
dpyptr = dpymsg;
|
// And the UART message / 18 characters
|
// And the UART message / 18 characters
|
uartptr = uartmsg;
|
uartptr = uartmsg;
|
*uartptr++ = '\r'; *uartptr++ = '\n';
|
strcat(uartptr, "\r\nDoorbell!\r\n\r\n");
|
*uartptr++ = 'D';
|
|
*uartptr++ = 'o';
|
|
*uartptr++ = 'o';
|
|
*uartptr++ = 'r';
|
|
*uartptr++ = 'b';
|
|
*uartptr++ = 'e';
|
|
*uartptr++ = 'l';
|
|
*uartptr++ = 'l';
|
|
*uartptr++ = '!';
|
|
*uartptr++ = '\r'; *uartptr++ = '\n';
|
|
*uartptr++ = '\r'; *uartptr++ = '\n';
|
|
*uartptr++ = '\0';
|
|
uartptr = uartmsg;
|
uartptr = uartmsg;
|
|
|
|
|
seconds = 0;
|
seconds = 0;
|
sys->io_spio = 0x0ff; // All LED's on: we got one!
|
sys->io_spio = 0x0ff; // All LED's on: we got one!
|
sptr = sound_data;
|
sptr = sound_data;
|
sys->io_pwm_audio = 0x0310000; // Turn on the audio
|
sys->io_pwm_audio = 0x0310000; // Turn on the audio
|
while(sptr < &sound_data[NSAMPLE_WORDS]) {
|
while(sptr < &sound_data[NSAMPLE_WORDS]) {
|
do {
|
do {
|
|
TOUCH_WATCHDOG;
|
pic = sys->io_pic;
|
pic = sys->io_pic;
|
if (pic & INT_TIMA) {
|
if (pic & INT_TIMER) {
|
sys->io_pic = INT_TIMA;
|
sys->io_pic = INT_TIMER;
|
seconds++;
|
seconds++;
|
rtcclock = rtcnext(rtcclock);
|
rtcclock = rtcnext(rtcclock);
|
} if ((pic & INT_UARTTX)&&(*uartptr)) {
|
} if ((pic & INT_UARTTX)&&(*uartptr)) {
|
sys->io_uart = *uartptr++;
|
sys->io_uart = *uartptr++;
|
sys->io_pic = INT_UARTTX;
|
sys->io_pic = INT_UARTTX;
|
Line 222... |
Line 202... |
if (*dpyptr) {
|
if (*dpyptr) {
|
// This will take a long time. It should be an
|
// This will take a long time. It should be an
|
// interruptable task ... but, sigh, we're not
|
// interruptable task ... but, sigh, we're not
|
// there yet.
|
// there yet.
|
dispchar(*dpyptr++);
|
dispchar(*dpyptr++);
|
sys->io_spio = 0x44;
|
sys->io_spio = 0x45;
|
} else
|
} else
|
sys->io_spio = 0x40;
|
sys->io_spio = 0x40;
|
} while((pic & INT_AUDIO)==0);
|
} while((pic & INT_AUDIO)==0);
|
sys->io_pwm_audio = (*sptr >> 16)&0x0ffff;
|
sys->io_pwm_audio = (*sptr++) & 0x0ffff;
|
// Now, turn off the audio interrupt since it doesn't
|
// Now, turn off the audio interrupt since it doesn't
|
// reset itself ...
|
// reset itself ...
|
sys->io_pic = INT_AUDIO;
|
sys->io_pic = INT_AUDIO;
|
|
|
do {
|
|
pic = sys->io_pic;
|
|
|
|
if (pic & INT_TIMA) {
|
|
sys->io_pic = INT_TIMA;
|
|
seconds++;
|
|
rtcclock = rtcnext(rtcclock);
|
|
} if ((pic & INT_UARTTX)&&(*uartptr)) {
|
|
sys->io_uart = *uartptr++;
|
|
sys->io_pic = INT_UARTTX;
|
|
sys->io_spio = 0x22;
|
|
} else if (!*uartptr)
|
|
sys->io_spio = 0x20;
|
|
if (*dpyptr) {
|
|
// This will take a long time. It should be an
|
|
// interruptable task ... but, sigh, we're not
|
|
// there yet.
|
|
dispchar(*dpyptr++);
|
|
sys->io_spio = 0x44;
|
|
} else
|
|
sys->io_spio = 0x40;
|
|
} while((pic & INT_AUDIO)==0);
|
|
sys->io_pwm_audio = (*sptr++) & 0x0ffff;
|
|
|
|
// and turn off the audio interrupt again ...
|
|
sys->io_pic = INT_AUDIO;
|
|
} sys->io_pic = INT_BUTTON;
|
} sys->io_pic = INT_BUTTON;
|
|
sys->io_spio = 0x10;
|
|
|
|
TOUCH_WATCHDOG;
|
// Now we wait for the end of our 30 second window
|
// Now we wait for the end of our 30 second window
|
sys->io_spio = 0x0f8;
|
sys->io_spio = 0x0f8;
|
sys->io_pwm_audio = 0x018000; // Turn off the Audio device
|
sys->io_pwm_audio = 0x018000; // Turn off the Audio device
|
while(seconds < 30) {
|
while(seconds < 30) {
|
|
TOUCH_WATCHDOG;
|
pic = sys->io_pic;
|
pic = sys->io_pic;
|
if (pic & INT_TIMA) {
|
if (pic & INT_TIMER) {
|
sys->io_pic = INT_TIMA;
|
sys->io_pic = INT_TIMER;
|
seconds++;
|
seconds++;
|
rtcclock = rtcnext(rtcclock);
|
rtcclock = rtcnext(rtcclock);
|
} if (pic & INT_BUTTON) {
|
} if (pic & INT_BUTTON) {
|
sys->io_pic = INT_BUTTON;
|
sys->io_pic = INT_BUTTON;
|
seconds = 0;
|
seconds = 0;
|
}
|
}
|
} sys->io_pic = INT_BUTTON;
|
} sys->io_pic = INT_BUTTON;
|
|
TOUCH_WATCHDOG;
|
}
|
}
|
}
|
}
|
|
|
void build_dpymsg(char *msg, unsigned clk) {
|
void build_dpymsg(char *msg, unsigned clk) {
|
*msg++ = (0x1b<<24)|('['<<16)|('j'<<8)|'C'; // Clear, and start 'C'
|
msg[0] = 0x1b;
|
*msg++ = ('l'<<24)|('o'<<16)|('c'<<8)|'k';
|
strcpy(++msg, "[jClock : ");
|
*msg = (' '<<24)|(':'<<16)|(' '<<8);
|
msg += strlen(msg);
|
|
|
if ((clk>>20)&0x0f)
|
if ((clk>>20)&0x0f)
|
*msg++ |= (((clk>>20)&0x0f)+'0');
|
*msg++ |= (((clk>>20)&0x0f)+'0');
|
else
|
else
|
*msg++ |= ' ';
|
*msg++ |= ' ';
|
*msg++ = ((((clk>>16)&0x0f)+'0')<<24)
|
*msg++ = (((clk>>16)&0x0f)+'0');
|
|(':'<<16)
|
*msg++ = ':';
|
|((((clk>>12)&0x0f)+'0')<< 8) // Minutes
|
*msg++ = (((clk>>12)&0x0f)+'0');
|
|((((clk>> 8)&0x0f)+'0') );
|
*msg++ = (((clk>> 8)&0x0f)+'0');
|
*msg++ = (':'<<24)
|
*msg++ = ':';
|
|((((clk>> 4)&0x0f)+'0')<<16) // Seconds
|
*msg++ = (((clk>> 4)&0x0f)+'0');
|
|((((clk )&0x0f)+'0')<< 8);
|
*msg++ = (((clk )&0x0f)+'0');
|
*msg++ = 0;
|
|
*msg++ = 0;
|
|
*msg++ = 0;
|
|
*msg++ = 0;
|
*msg++ = 0;
|
}
|
}
|
|
|
void build_uartmsg(char *msg, unsigned clk) {
|
void build_uartmsg(char *msg, unsigned clk) {
|
*msg++ = 'T'; // 0
|
strcpy(msg, "Time: ");
|
*msg++ = 'i'; // 1
|
msg += strlen(msg);
|
*msg++ = 'm'; // 2
|
|
*msg++ = 'e'; // 3
|
|
*msg++ = ':'; // 4
|
|
*msg++ = ' ';
|
|
*msg++ = ((clk>>20)&0x03)+'0'; // Hrs
|
*msg++ = ((clk>>20)&0x03)+'0'; // Hrs
|
*msg++ = ((clk>>16)&0x0f)+'0';
|
*msg++ = ((clk>>16)&0x0f)+'0';
|
*msg++ = ':';
|
*msg++ = ':';
|
*msg++ = ((clk>>12)&0x0f)+'0'; // Mins
|
*msg++ = ((clk>>12)&0x0f)+'0'; // Mins
|
*msg++ = ((clk>> 8)&0x0f)+'0';
|
*msg++ = ((clk>> 8)&0x0f)+'0';
|
Line 328... |
Line 279... |
ch = ch - '0'+'A'-10;
|
ch = ch - '0'+'A'-10;
|
dispchar(ch);
|
dispchar(ch);
|
}
|
}
|
}
|
}
|
|
|
void txch(int val) {
|
|
register IOSPACE *sys = (IOSPACE *)0x0100;
|
|
|
|
// To read whether or not the transmitter is ready, you must first
|
|
// clear the interrupt bit.
|
|
sys->io_pic = INT_UARTTX;
|
|
for(int i=0; i<5000; i++)
|
|
asm("noop");
|
|
sys->io_pic = INT_UARTTX;
|
|
// If the interrupt bit sets itself again immediately, the transmitter
|
|
// is ready. Otherwise, wait until the transmitter becomes ready.
|
|
while((sys->io_pic&INT_UARTTX)==0)
|
|
;
|
|
sys->io_uart = (val&0x0ff);
|
|
// Give the transmitter a chance to finish, and then to create an
|
|
// interrupt when done
|
|
sys->io_pic = INT_UARTTX;
|
|
}
|
|
|
|
void txval(int val) {
|
|
txch('\r');
|
|
txch('\n');
|
|
txch('0');
|
|
txch('x');
|
|
for(int i=28; i>=0; i-=4) {
|
|
int ch = ((val>>i)&0x0f)+'0';
|
|
if (ch > '9')
|
|
ch = ch - '0'+'A'-10;
|
|
txch(ch);
|
|
}
|
|
}
|
|
|
|
// PPONP16P
|
|
// 00120O91
|
|
// 00120NM3
|
|
// 00120E91 = 1183377 ~= 91029 / char, at 0x208d 8333/baud, 83,330 per char
|
|
|
|
No newline at end of file
|
No newline at end of file
|