MPLAB Xpress: MP3 click piano
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/******************************************************************* | |
____ __ ____ ___ ____ ____ __ __ _ ____ __ | |
( __)( ) ( __)/ __)(_ _)( _ \ / \ ( ( \(__ ) / _\ | |
) _) / (_/\ ) _)( (__ )( ) /( O )/ / / _/ / \ | |
(____)\____/(____)\___) (__) (__\_) \__/ \_)__)(____)\_/\_/ | |
Project name: MPLAB Xpress: MP3 click piano | |
Project page: https://electronza.com/mplab-xpress-mp3-click-piano/ | |
********************************************************************/ | |
/** | |
Generated Main Source File | |
Company: | |
Microchip Technology Inc. | |
File Name: | |
main.c | |
Summary: | |
This is the main file generated using MPLAB(c) Code Configurator | |
Description: | |
This header file provides implementations for driver APIs for all modules selected in the GUI. | |
Generation Information : | |
Product Revision : MPLAB(c) Code Configurator - v3.00 | |
Device : PIC16F18855 | |
Driver Version : 2.00 | |
The generated drivers are tested against the following: | |
Compiler : XC8 1.35 | |
MPLAB : MPLAB X 3.20 | |
*/ | |
/* | |
Copyright (c) 2013 - 2015 released Microchip Technology Inc. All rights reserved. | |
Microchip licenses to you the right to use, modify, copy and distribute | |
Software only when embedded on a Microchip microcontroller or digital signal | |
controller that is integrated into your product or third party product | |
(pursuant to the sublicense terms in the accompanying license agreement). | |
You should refer to the license agreement accompanying this Software for | |
additional information regarding your rights and obligations. | |
SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, | |
EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF | |
MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. | |
IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER | |
CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR | |
OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES | |
INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR | |
CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF | |
SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES | |
(INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. | |
*/ | |
#include "mcc_generated_files/mcc.h" | |
/* | |
Main application | |
*/ | |
// **************************************************************************************** | |
// VS1053 / MP3 click connections | |
// VS1053 uses SPI communication | |
// See VS1053 datasheet for more info | |
// SCK - RB3 (pin initialized by MCC) | |
// SDO (MOSI) - RB5 (pin initialized by MCC) | |
// SDI (MISO) - RB4 (pin initialized by MCC) | |
// CS# - RB2 (set PIC16F18855 pin as output) - Control Chip Select (to access registers) | |
// RST# - RB1 (set PIC16F18855 pin as output) - Reset | |
// DREQ - RB0 (set PIC16F18855 pin as input) - Data Request Pin: asks for more data | |
// DCS - RC2 (set PIC16F18855 pin as output) - Data Chip Select / BSYNC Pin | |
// **************************************************************************************** | |
// INFO FROM VLSI PATCH PAGE: http://www.vlsi.fi/en/support/software/vs10xxpatches.html | |
// These are binary patch files that can easily be loaded to the memory of your VS10XX by | |
// a microcontroller to fix known firmware bugs. Also, in some cases the patch set adds new | |
// functionality (example: FLAC decoding for VS1053b). | |
// VS1053b Realtime MIDI Start code | |
// Starts the real-time MIDI mode with a few SCI writes. | |
// Version: 1.0 | |
// Modified: 2009-01-12 | |
// Devices: VS1053b | |
// Link: http://www.vlsi.fi/fileadmin/software/VS10XX/vs1053b-rtmidistart.zip | |
// See also the pdf file inside that archive | |
const unsigned short VS1053b_Realtime_MIDI[28] = { | |
0x0007, 0x0001, 0x8050, 0x0006, 0x0014, 0x0030, 0x0715, 0xb080, /* 8 */ | |
0x3400, 0x0007, 0x9255, 0x3d00, 0x0024, 0x0030, 0x0295, 0x6890, /* 16 */ | |
0x3400, 0x0030, 0x0495, 0x3d00, 0x0024, 0x2908, 0x4d40, 0x0030, /* 24 */ | |
0x0200, 0x000a, 0x0001, 0x0050,}; /* 28 */ | |
// **************************************************************************************** | |
// Keyboard MIDI lookup codes | |
// Key: 0 1 2 3 4 5 6 7 8 9 | |
// Ascii code: 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 | |
// Note: C#5 D#5 F#5 G#5 A#5 C#6 D#6 | |
// MIDI code: 0x57 0x49 0x4B 0x4E 0x50 0x52 0x55 | |
const unsigned short NLookup_table [10] = {0x57, 0x00, 0x49, 0x4B, 0x00, | |
0x4E, 0x50, 0x52, 0x00, 0x55, }; | |
// Key: A B C D E F G H I J | |
// ASCII code: 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4A | |
// Note: G4 C4 D#4 E5 F#4 G#4 C6 A#4 | |
// MIDI code: 0x43 0x3C 0x3F 0x4C 0x42 0x44 0x54 0x46 | |
const unsigned short LLookup_table [26] = {0x00, 0x43, 0x3C, 0x3F, 0x4C, | |
0x00, 0x42, 0x44, 0x54, 0x46, | |
// Key: K L M N O P Q R S T | |
// ASCII code: 0x4B 0x4C 0x4D 0x4E 0x4F 0x50 0x51 0x52 0x53 0x54 | |
// Note: B4 A4 D6 E6 C5 F5 C#4 G5 | |
// MIDI code: 0x47 0x45 0x56 0x58 0x48 0x4D 0x3D 0x4F | |
0x00, 0x00, 0x47, 0x45, 0x56, 0x58, 0x48, 0x4D, 0x3D, 0x4F, | |
// Key: U V W X Y Z | |
// ASCII code: 0x55 0x56 0x57 0x58 0x59 0x5A | |
// Note: B5 F4 D5 D4 A5 4C | |
// MIDI code: 0x53 0x41 0x4A 0x3E 0x51 0x3C | |
0x53, 0x41, 0x4A, 0x3E, 0x51, 0x3C, }; | |
unsigned char keypress; | |
unsigned char mynote; | |
// Wait_for_DREQ is a blocking function | |
// All it does is to wait for DREQ to go high indicating IC is available | |
void Wait_for_DREQ (void){ | |
int DREQ_status; | |
DREQ_status = DREQ_GetValue(); | |
while (DREQ_status == 0){ | |
// update DREQ status | |
DREQ_status = DREQ_GetValue(); | |
} | |
} | |
// Write to VS10xx register | |
// SCI: Data transfers are always 16bit. When a new SCI operation comes in | |
// DREQ goes low. We then have to wait for DREQ to go high again. | |
// XCS should be low for the full duration of operation. | |
void VSWriteRegister(unsigned char addressbyte, unsigned char highbyte, unsigned char lowbyte){ | |
//Wait for DREQ to go high indicating IC is available | |
Wait_for_DREQ(); | |
// CS# should be low for the full duration of operation | |
CS_SetLow(); | |
//SCI consists of instruction byte, address byte, and 16-bit data word. | |
SPI1_Exchange8bit(0x02); // Write instruction | |
SPI1_Exchange8bit(addressbyte); // Destination register | |
SPI1_Exchange8bit(highbyte); // MSB | |
SPI1_Exchange8bit(lowbyte); // LSB | |
//Wait for DREQ to go high indicating command is complete | |
Wait_for_DREQ(); | |
//Deselect Control | |
CS_SetHigh(); | |
} | |
// This function loads the MIDI plugin | |
void VSLoadUserCode(void) | |
{ | |
unsigned int i = 0; | |
while (i < sizeof(VS1053b_Realtime_MIDI) / sizeof(VS1053b_Realtime_MIDI[0])) { | |
unsigned short addr, n, val; | |
addr = VS1053b_Realtime_MIDI[i++]; | |
n = VS1053b_Realtime_MIDI[i++]; | |
while (n--) { | |
val = VS1053b_Realtime_MIDI[i++]; | |
VSWriteRegister(addr, val >> 8, val & 0xFF); | |
} | |
} | |
} | |
void sendMIDI(uint8_t data) | |
{ | |
SPI1_Exchange8bit(0x00); | |
SPI1_Exchange8bit(data); | |
} | |
// Plays a MIDI note. Doesn't check to see that cmd is greater than 127, | |
// or that data values are less than 127 | |
void talkMIDI(uint8_t cmd, uint8_t data1, uint8_t data2) { | |
// Wait for chip to be ready (Unlikely to be an issue with real time MIDI) | |
Wait_for_DREQ(); | |
// Set DCS to low (sending data) | |
DCS_SetLow(); | |
sendMIDI(cmd); | |
// Some commands only have one data byte. All cmds less than 0xBn have 2 data bytes | |
// (sort of: http://253.ccarh.org/handout/midiprotocol/) | |
if( (cmd & 0xF0) <= 0xB0 || (cmd & 0xF0) >= 0xE0) { | |
sendMIDI(data1); | |
sendMIDI(data2); | |
} else { | |
sendMIDI(data1); | |
} | |
// We sent the command, now we set DCS to high | |
DCS_SetHigh(); | |
} | |
//Send a MIDI note-on message. Like pressing a piano key | |
//channel ranges from 0-15 | |
void noteOn(uint8_t channel, uint8_t note, uint8_t attack_velocity) { | |
talkMIDI( (0x90 | channel), note, attack_velocity); | |
} | |
//Send a MIDI note-off message. Like releasing a piano key | |
void noteOff(uint8_t channel, uint8_t note, uint8_t release_velocity) { | |
talkMIDI( (0x80 | channel), note, release_velocity); | |
} | |
void main(void) | |
{ | |
// initialize the device | |
SYSTEM_Initialize(); | |
// When using interrupts, you need to set the Global and Peripheral Interrupt Enable bits | |
// Use the following macros to: | |
// Enable the Global Interrupts | |
INTERRUPT_GlobalInterruptEnable(); | |
// Enable the Peripheral Interrupts | |
INTERRUPT_PeripheralInterruptEnable(); | |
// Disable the Global Interrupts | |
//INTERRUPT_GlobalInterruptDisable(); | |
// Disable the Peripheral Interrupts | |
//INTERRUPT_PeripheralInterruptDisable(); | |
printf("MP3 click \n\r"); | |
// Hardware reset of VS1053 | |
RST_SetLow(); // Put VS1053 into hardware reset | |
DCS_SetHigh(); | |
CS_SetHigh(); | |
__delay_ms(10); // Wait... | |
RST_SetHigh(); // Bring up VS1053 | |
__delay_ms(10); // Wait... | |
printf("Reset \n\r"); | |
// Then we load the MIDI plugin | |
VSLoadUserCode(); | |
printf("Patch loaded \n\r"); | |
// miditest | |
talkMIDI(0xB0, 0x07, 120); // 0xB0 is channel message, set channel volume to near max (127) | |
talkMIDI(0xB0, 0, 0x00); // Default bank GM1 | |
talkMIDI(0xC0, 0x01, 0); // Set instrument number. 0xC0 is a 1 data byte command | |
// 0x01 Acoustic Grand Piano | |
// 0x02 Bright Acoustic Piano | |
// See page 33 of VS1053 datasheet | |
//Play notes from F#-0 (30) to F#-5 (90): | |
for (int note = 30 ; note < 40 ; note++) { | |
//Note on channel 1 (0x90), some note value (note), middle velocity (0x45): | |
noteOn(0, note, 127); | |
__delay_ms(200); | |
//Turn off the note with a given off/release velocity | |
noteOff(0, note, 127); | |
__delay_ms(50); | |
} | |
// Now waiit for keyboard input | |
while (1) | |
{ | |
// Add your application code | |
// Read a key | |
keypress = getch(); | |
putch(keypress); // local echo | |
if ((keypress >= 0x30) && (keypress <= 0x39)) // is a number | |
{ | |
keypress = keypress - 0x30; // remove offset | |
mynote = NLookup_table [keypress]; // get note | |
if(mynote > 0) // valid note | |
{ | |
noteOn(0, mynote, 127); | |
__delay_ms(200); | |
//Turn off the note with a given off/release velocity | |
noteOff(0, mynote, 127); | |
__delay_ms(50); | |
} | |
} | |
if ((keypress >= 0x41) && (keypress <= 0x5A)) // is uppercase letter | |
{ | |
keypress = keypress - 0x41; // remove offset | |
mynote = LLookup_table [keypress]; // get note | |
if(mynote > 0) // valid note | |
{ | |
noteOn(0, mynote, 127); | |
__delay_ms(200); | |
//Turn off the note with a given off/release velocity | |
noteOff(0, mynote, 127); | |
__delay_ms(50); | |
} | |
} | |
if ((keypress >= 0x61) && (keypress <= 0x7A)) // is a lowercase letter | |
{ | |
keypress = keypress - 0x61; // remove offset | |
mynote = LLookup_table [keypress]; // get note | |
if(mynote > 0) // valid note | |
{ | |
noteOn(0, mynote, 127); | |
__delay_ms(200); | |
//Turn off the note with a given off/release velocity | |
noteOff(0, mynote, 127); | |
__delay_ms(50); | |
} | |
} | |
} | |
} | |
/** | |
End of File | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment