Skip to content

Instantly share code, notes, and snippets.

@Electronza
Created Dec 19, 2019
Embed
What would you like to do?
MPLAB Xpress: MP3 click piano
/*******************************************************************
____ __ ____ ___ ____ ____ __ __ _ ____ __
( __)( ) ( __)/ __)(_ _)( _ \ / \ ( ( \(__ ) / _\
) _) / (_/\ ) _)( (__ )( ) /( 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