Skip to content

Instantly share code, notes, and snippets.

@Aflecht
Last active August 29, 2015 13:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Aflecht/9380101 to your computer and use it in GitHub Desktop.
Save Aflecht/9380101 to your computer and use it in GitHub Desktop.
MIDI I/O with NXP LPC43xx micro controller (ARM Cortex M4 MCU)
#define CMSIS_BITPOSITIONS
#include <__cross_studio_io.h>
#include "lpc43xx.h"
//
// Configure LPC43xx ARM Cortex M4 microcontroller to 204 MHz using 12 MHz crystal
//
void Configure_Main_Clock_And_Busses()
{
// Enable crystal oscillator
LPC_CGU->XTAL_OSC_CTRL = 0;
for (volatile uint32_t i = 0; i < 1000000; ++i);
// Set the PLL to 204 MHz
uint32_t control_register = LPC_CGU->PLL1_CTRL;
control_register &= ~(CGU_PLL1_CTRL_MSEL_Msk | CGU_PLL1_CTRL_CLK_SEL_Msk | CGU_PLL1_CTRL_PD_Msk);
control_register |= 16 << CGU_PLL1_CTRL_MSEL_Pos; // Feedback-divider division ratio = 17 ---> 17 * 12 MHz = 204 MHz
control_register |= 6 << CGU_PLL1_CTRL_CLK_SEL_Pos; // Clock source = crystal oscillator
LPC_CGU->PLL1_CTRL = control_register;
while (!(LPC_CGU->PLL1_STAT & CGU_PLL1_STAT_LOCK_Msk));
// Set M4 clock to PLL1
LPC_CGU->BASE_M4_CLK = 9 << CGU_BASE_M4_CLK_CLK_SEL_Pos | // Clock source = PLL1
1 << CGU_BASE_M4_CLK_AUTOBLOCK_Pos; // Block clock automatically during frequency change
// Set PERIPH clock to PLL1
LPC_CGU->BASE_PERIPH_CLK = 9 << CGU_BASE_PERIPH_CLK_CLK_SEL_Pos | // Clock source = PLL1
1 << CGU_BASE_PERIPH_CLK_AUTOBLOCK_Pos; // Block clock automatically during frequency change
// Set APB1 clock to PLL1
LPC_CGU->BASE_APB1_CLK = 9 << CGU_BASE_APB1_CLK_CLK_SEL_Pos | // Clock source = PLL1
1 << CGU_BASE_APB1_CLK_AUTOBLOCK_Pos; // Block clock automatically during frequency change
// Set APB3 clock to PLL1
LPC_CGU->BASE_APB3_CLK = 9 << CGU_BASE_APB3_CLK_CLK_SEL_Pos | // Clock source = PLL1
1 << CGU_BASE_APB3_CLK_AUTOBLOCK_Pos; // Block clock automatically during frequency change
}
/*
Use UART1 input & output for MIDI.
Pin P1_13 = MIDI output
Pin P1_14 = MIDI input
------------
Crystal = 12 MHz
MIDI baud rate = 31250
12 MHz / 31250 = 384 cycles per baud
UART is always 16x oversampling.
*/
void Configure_MIDI_IO()
{
// Set UART1 clock to crystal
LPC_CGU->BASE_UART1_CLK |= 6 << CGU_BASE_UART1_CLK_CLK_SEL_Pos | // UART1 clock source = Crystal
1 << CGU_BASE_UART1_CLK_AUTOBLOCK_Pos; // Block clock automatically during frequency change
// MIDI format = 31250 baud, 1 start bit, 8 data, no parity, 1 stop bit
LPC_UART1->LCR |= 3 << UART1_LCR_WLS_Pos | // 8bit character length
UART1_LCR_DLAB_Msk; // Enable Divisor Latch Access
LPC_UART1->DLL &= ~UART1_DLL_DLLSB_Msk;
LPC_UART1->DLL |= 24 << UART1_DLL_DLLSB_Pos; // 12MHz clock, 31250 baud, 16x oversampling ---> 12MHz / (16 * 31250) = 24
LPC_UART1->LCR &= ~UART1_LCR_DLAB_Msk; // Disable Divisor Latch Access
LPC_UART1->FCR |= UART1_FCR_FIFOEN_Msk; // Enable FIFO
// Set pin functionalities
LPC_SCU->SFSP1_13 |= 1 << SCU_SFSP1_13_MODE_Pos; // P1_13 = FUNC1 = UART1 TXD = MIDI-OUT-1
LPC_SCU->SFSP1_14 |= 1 << SCU_SFSP1_14_MODE_Pos; // P1_14 = FUNC1 = UART1 RXD = MIDI-IN-1
LPC_SCU->SFSP1_14 |= SCU_SFSP1_14_EZI_Msk; // P1_14 = Enable input buffer
}
void Send_MIDI_Message(uint32_t message_24bit)
{
while (!(LPC_UART1->LSR & UART1_LSR_THRE_Msk)); // Wait until UART1 THR is empty
LPC_UART1->THR = (message_24bit >> 16) & 0xFF;
while (!(LPC_UART1->LSR & UART1_LSR_THRE_Msk));
LPC_UART1->THR = (message_24bit >> 8) & 0xFF;
while (!(LPC_UART1->LSR & UART1_LSR_THRE_Msk));
LPC_UART1->THR = message_24bit & 0xFF;
}
void main(void)
{
Configure_Main_Clock_And_Busses();
Configure_MIDI_IO();
// MIDI input test
while (1)
{
if (LPC_UART1->LSR & UART1_LSR_RDR_Msk)
debug_printf("%x ", LPC_UART1->RBR & 0xFF);
}
/*
// MIDI output test
while (1)
{
Send_MIDI_Message(0x0090017F); // Note on
for (volatile uint32_t i = 0; i < 4000000; ++i);
Send_MIDI_Message(0x00900100); // Note off
for (volatile uint32_t i = 0; i < 8000000; ++i);
}
*/
}
@Aflecht
Copy link
Author

Aflecht commented Mar 6, 2014

This example uses NXP LPC4330FBD144 microcontroller.
It's should be usable with other LPC43xx microcontrollers with minimal changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment