rotl_quotes/main.cpp

208 lines
6.0 KiB
C++

/*
* File: main.c
* Author: amr
*
* Created on September 26, 2020, 3:32 AM
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "fuses.hpp"
#include <xc.h>
#include <sys/attribs.h>
#include <stdint.h>
#include <stdlib.h>
#include "i2c.hpp"
#include "FIFO.hpp"
#include "FlashStorage.hpp"
#include "UART.hpp"
#define STATE_IDLE 0
#define STATE_PLAYING 1
#define STATE_PROGRAMMING 2
uint8_t globalState = 1;
// Flash data variables
volatile uint32_t flashAddress = 0;
volatile uint32_t byteCount = 0;
volatile uint32_t readByteCount = 0;
volatile uint8_t currentClip = 0;
// Audio clip address table
#define AUDIO_SIZE 509176
const uint32_t audioSize[16] = { 0x0000ba8d, 0x0000d063, 0x000069fa, 0x00007c3e,
0x000030b4, 0x0000c676, 0x000020fd, 0x00005314, 0x00002db8, 0x00002fbd,
0x000046c0, 0x0000bc92, 0x0000a257, 0x00002830, 0x00011790, 0x0000a5b7
};
const uint32_t audioAddress[16] = { 0x00, 0x0000ba8d, 0x00018af0, 0x0001f4ea,
0x00027128, 0x0002a1dc, 0x00036852, 0x0003894f, 0x0003dc63, 0x00040a1b,
0x000439d8, 0x00048098, 0x00053d2a, 0x0005df81, 0x000607b1, 0x00071f41
};
#define dacAddress 0x62
void _delay(uint32_t cycles) {
cycles += (uint32_t) ((double) cycles * 1.4);
while (cycles--);
return;
}
uint8_t initSystem(void) {
/* set up GPIO */
SYSKEY = 0x0;
SYSKEY = 0xAA996655;
SYSKEY = 0x556699AA;
CFGCON &= ~(1 << 13); // unlock PPS
// Pin configs
/* SPI:
* SO = RB5
* SI = RC8
* CS = RA4
*
* I2C:
* SDA: RB2
* SCL: RB3
*
* UART:
* TX = RC5
* RX = RC3
*/
SDI1R = 0b0110; // RC8
U1RXR = 0b0111; // RC3
RPC0R = 0b0101; // OC1 on LED
RPB5R = 0b0011; // SD01
RPC5R = 0b0001; // U1TX
OSCCONCLR = 0x00000010; // idle mode
SYSKEY = 0x12345678; // lock SYSKEY
ANSELACLR = 0xFFFF;
ANSELBCLR = 0xFFFF;
ANSELCCLR = 0xFFFF; // clear all analog functions
// set up LED
TRISCCLR = 0x01; // PC0 is LED
PORTCCLR = 0x01; // turn LED off at boot
// set up button with change interrupt
TRISASET = 0x200; // PA9 is button input
CNENASET = 0x200; // enable on PA9
CNPUASET = 0x200; // pullup enable
CNCONASET = 0x8000; // enable for port A
IFS1CLR = 0x2000;
IPC8SET = 0xC0000; // priority 3
IEC1SET = 0x2000; // enable pin change interrupt port A
/* Set up SPI1 */
TRISACLR = 0x10;
PORTASET = 0x10;
TRISBCLR = 0x4000; // RB14 is SCK1
SPI1BRG = 1; // 2.5MHz
SPI1CONbits.ENHBUF = 0; // enable enhanced buffer
SPI1CONbits.MSTEN = 1; // master mode
SPI1STATCLR = (1 << 6); // clear SPIROV
SPI1CONbits.ON = 1; // enable SPI
// set up timer (needs to be about 8kHz)
T2CON = 0x0000; // timer continues in idle mode
PR2 = 0x04E2; // 1250 = 10e6/8e3
TMR2 = 0x0000;
IPC2bits.T2IP = 7; // priority 7
IFS0bits.T2IF = 0;
IEC0bits.T2IE = 1; // enable timer interrupt
INTCONSET = _INTCON_MVEC_MASK;
return 0;
}
void updateDAC(i2c *bus, uint16_t data) {
uint8_t bytes[2] = {0x00, 0x00};
bytes[0] = (uint8_t) (data >> 8) & 0x0F; // clear top half of top byte
bytes[1] = (uint8_t) (data & 0x00FF);
bus->transact(dacAddress, bytes, NULL, 2, MULTIPLE_SEND);
}
int main(void) {
volatile uint16_t audioSampleShifted = 0;
volatile uint8_t audioSample = 0;
initSystem();
FIFO audioBuffer(64);
UART serial(19200, 10e6);
FlashStorage flash(&audioBuffer, &serial);
i2c i2cBus(400e3, 10e6);
// this needs to be as early as possible, but after SPI and UART setup
if(!(LATC & 0x20)) {
// if button is held down at boot, it's programming mode
globalState = STATE_PROGRAMMING;
flash.program();
}
const char testString[20] = "Welcome to Canada\n\r";
// main state machine loop
//flash.program();
globalState == STATE_PLAYING;
while (1) {
__builtin_disable_interrupts();
if (globalState == STATE_PLAYING) {
if (audioBuffer.usedSize < 16) {
// read 48 bytes into buffer
flash.read(audioAddress[currentClip] + readByteCount, 48);
readByteCount += 48;
}
audioSample = audioBuffer.read();
byteCount++;
if (byteCount >= audioSize[currentClip]) {
byteCount = 0;
readByteCount = 0;
//globalState = STATE_IDLE;
}
// Load sample into DAC
audioSampleShifted = (uint16_t) (audioSample << 4);
//updateDAC(&i2cBus, audioSampleShifted);
serial.send(audioSample);
__builtin_enable_interrupts();
T2CONbits.ON = 1; // enable timer
asm volatile("wait");
} else if (globalState == STATE_IDLE) {
for (uint8_t i = 0; i < 20; i++) {
serial.send(testString[i]);
}
__builtin_enable_interrupts();
T2CONbits.ON = 1; // enable timer
asm volatile("wait");
}
}
}
extern "C" {
void __ISR(_TIMER_2_VECTOR, IPL7AUTO) Timer2Handler(void) {
T2CONbits.ON = 0;
IFS0bits.T2IF = 0;
}
void __ISR(_CHANGE_NOTICE_VECTOR, IPL3AUTO) PinChangeHandler(void) {
if((IFS1 & 0x2000) || (CNSTATA & 0x200)) {
if(PORTA) ; // dummy read to reset change notice
// button is pushed
if (globalState == STATE_PLAYING) {
return; // do nothing, we're already playing
}
// pick a random number
currentClip += 1;
currentClip = currentClip % 8; // roll back around
globalState = STATE_PLAYING;
IFS1CLR = 0x00002000;
}
}
} // end extern C