Skip to content

Commit

Permalink
midi in and out working in a very basic form
Browse files Browse the repository at this point in the history
  • Loading branch information
trentgill committed Jun 4, 2024
1 parent 80358fc commit 649c2e2
Show file tree
Hide file tree
Showing 8 changed files with 256 additions and 28 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ SRC = main.c \
lib/metro.c \
lib/shapes.c \
lib/slopes.c \
lib/midi.c \
$(wildcard ll/*.c) \
$(wildcard usbd/*.c) \
$(USBD)/Core/Src/usbd_core.c \
Expand Down
23 changes: 23 additions & 0 deletions lib/midi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include "midi.h"

#include <stdio.h>
#include "caw.h"

static void MIDI_handler(uint8_t byte);

void MIDI_init(Midi* m, Uart* transmit){
m->uart_tx = transmit;
}

void MIDI_transmit(Midi* m, uint8_t* bytes, int length){
// FIXME this should be passed in as a protocol
UART_send(m->uart_tx, bytes, length);
}

U8_Callback MIDI_get_callback(Midi* m){
return &MIDI_handler;
}

static void MIDI_handler(uint8_t byte){
Caw_printf("m 0x%x\n\r", byte);
}
14 changes: 14 additions & 0 deletions lib/midi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once

#include <stdint.h>
#include "../ll/uart.h" // this requirement should be dropped by replacing Uart* with a "protocol" of pointer + operations

typedef struct{
Uart* uart_tx;
} Midi;

void MIDI_init(Midi* m, Uart* transmit);

void MIDI_transmit(Midi* m, uint8_t* bytes, int length);

U8_Callback MIDI_get_callback(Midi* m);
56 changes: 47 additions & 9 deletions ll/system.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,22 +82,60 @@ static void MPU_Config(void)

HAL_MPU_Disable();

// Configure the MPU attributes as WT for SRAM
/*
// disable speculative access to unused memory region
mpu.Enable = MPU_REGION_ENABLE;
// mpu.Enable = MPU_REGION_DISABLE;
mpu.BaseAddress = 0x20020000;
// mpu.BaseAddress = 0x20000000;
mpu.Size = MPU_REGION_SIZE_256KB;
mpu.AccessPermission = MPU_REGION_FULL_ACCESS;
mpu.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
mpu.IsCacheable = MPU_ACCESS_CACHEABLE;
mpu.IsShareable = MPU_ACCESS_SHAREABLE;
mpu.Number = MPU_REGION_NUMBER0;
mpu.BaseAddress = 0;
mpu.Size = MPU_REGION_SIZE_4GB;
mpu.SubRegionDisable = 0x87;
mpu.TypeExtField = MPU_TEX_LEVEL0;
mpu.AccessPermission = MPU_REGION_NO_ACCESS;
mpu.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
mpu.IsShareable = MPU_ACCESS_SHAREABLE;
mpu.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
mpu.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
HAL_MPU_ConfigRegion(&mpu);
*/

// disable speculative access to unused memory region
mpu.Enable = MPU_REGION_ENABLE;
mpu.Number = MPU_REGION_NUMBER1;
mpu.BaseAddress = 0x20000000;
mpu.Size = MPU_REGION_SIZE_512KB;
mpu.SubRegionDisable = 0x00;
mpu.TypeExtField = MPU_TEX_LEVEL0;
mpu.AccessPermission = MPU_REGION_FULL_ACCESS;
mpu.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
mpu.IsShareable = MPU_ACCESS_SHAREABLE;
mpu.IsCacheable = MPU_ACCESS_CACHEABLE;
mpu.IsBufferable = MPU_ACCESS_BUFFERABLE;
HAL_MPU_ConfigRegion(&mpu);

/*
// very conservative (no cache) to try and crush bug
mpu.Enable = MPU_REGION_ENABLE;
mpu.Number = MPU_REGION_NUMBER1;
// mpu.BaseAddress = 0x20020000;
mpu.BaseAddress = 0x20000000;
mpu.Size = MPU_REGION_SIZE_512KB;
mpu.SubRegionDisable = 0x07;
// 2 options for normal mode with writeback approach
// no write allocate: tex=0, cachable & bufferable, sharable optional
// write & read allocate: tex=1, cachable & bufferable, shareable optional
// best practice is to place dma buffers at a specific location & set that region only as shareable
// then the remainder of ram can stay as cachable
mpu.TypeExtField = MPU_TEX_LEVEL0;
mpu.AccessPermission = MPU_REGION_FULL_ACCESS;
mpu.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
mpu.IsShareable = MPU_ACCESS_NOT_SHAREABLE; // shareable essentially disables cache
mpu.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
mpu.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
// HAL_MPU_ConfigRegion(&mpu);
*/
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

// // Configure the MPU attributes as WT for SRAM
Expand Down
1 change: 1 addition & 0 deletions ll/timers.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <stdio.h>

#include "interrupts.h"
#include "../lib/caw.h"

#define MAX_LL_TIMERS 11 // tell caller how many timers can be allocated

Expand Down
111 changes: 111 additions & 0 deletions ll/uart.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#include "uart.h"

#include <stdio.h>
#include "../lib/caw.h"
#include "debug_pin.h"

static Uart* selves[2]; // for callbacks
static Uart* _self; // for MSP init

static uint8_t rx_buffer[1] = {0}; // buffer for reception. TODO extend to circular buffer & pass length

Uart* UART_init(Uart* self, UART_Direction dir, USART_TypeDef* instance, char* pin){
selves[dir] = self; // for interrupt lookup

self->hUart.Instance = instance;
self->hUart.Init.BaudRate = 31250;
self->hUart.Init.WordLength = UART_WORDLENGTH_8B;
self->hUart.Init.StopBits = UART_STOPBITS_1;
self->hUart.Init.Parity = UART_PARITY_NONE;
self->hUart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
self->hUart.Init.OverSampling = UART_OVERSAMPLING_16;

if(dir == UART_Rx){
self->hUart.Init.Mode = UART_MODE_RX;
} else if(dir == UART_Tx){
self->hUart.Init.Mode = UART_MODE_TX;
}

_self = self;
if(HAL_UART_Init(&self->hUart) != HAL_OK){
Caw_printf("uart failed to init %i\n\r", dir);
Debug_Pin_Set(2, 1);
}
_self = NULL;

return self;
}

void UART_set_callback(Uart* self, U8_Callback callback){
self->cb_handler = callback;

// start reception loop once callback is registered
if(HAL_UART_Receive_IT(&self->hUart, rx_buffer, 1) != HAL_OK){
Caw_printf("failed to start reception\n\r");
Debug_Pin_Set(2, 1);
}
}

void UART_send(Uart* self, uint8_t* data, size_t len){
// FIXME currently blocking!
// TODO use IRQ mode & ignore response, or use DMA mode if we need longer messages (sysex)
HAL_UART_Transmit(&self->hUart, data, len, 1000);
// HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
// HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
}


// FIXME all the pin mapping is hard coded right now
// FIXME interrupt priorities. only needed on RX channel
void HAL_UART_MspInit(UART_HandleTypeDef* huart){
GPIO_InitTypeDef g;
g.Mode = GPIO_MODE_AF_PP;
g.Pull = GPIO_PULLUP;
g.Speed = GPIO_SPEED_FAST;
RCC_PeriphCLKInitTypeDef rcc;

// Select SysClk as source of USART1 clocks
if(huart->Instance == UART5){
__GPIOB_CLK_ENABLE(); // FIXME auto-select from _self->pinname
rcc.PeriphClockSelection = RCC_PERIPHCLK_UART5;
rcc.Uart5ClockSelection = RCC_UART5CLKSOURCE_SYSCLK;
HAL_RCCEx_PeriphCLKConfig(&rcc);
__UART5_CLK_ENABLE();
g.Pin = GPIO_PIN_8; // FIXME
g.Alternate = GPIO_AF7_UART5; // FIXME depends on pin mapping
HAL_GPIO_Init(GPIOB, &g);
HAL_NVIC_SetPriority(UART5_IRQn, 3, 1);
HAL_NVIC_EnableIRQ(UART5_IRQn);
} else if(huart->Instance == UART8){
__GPIOE_CLK_ENABLE(); // FIXME auto-select from _self->pinname
rcc.PeriphClockSelection = RCC_PERIPHCLK_UART8;
rcc.Uart8ClockSelection = RCC_UART8CLKSOURCE_SYSCLK;
HAL_RCCEx_PeriphCLKConfig(&rcc);
__UART8_CLK_ENABLE();
g.Pin = GPIO_PIN_1; // FIXME
g.Alternate = GPIO_AF8_UART8; // FIXME depends on pin mapping
HAL_GPIO_Init(GPIOE, &g);
// no callback for TX
// HAL_NVIC_SetPriority(UART8_IRQn, 3, 0);
// HAL_NVIC_EnableIRQ(UART8_IRQn);
}
}

void UART5_IRQHandler(void){
HAL_UART_IRQHandler(&selves[UART_Rx]->hUart);
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef* h){
// UNUSED
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef* h){
selves[UART_Rx]->cb_handler(rx_buffer[0]);
if(HAL_UART_Receive_IT(&selves[UART_Rx]->hUart, rx_buffer, 1) != HAL_OK){
Caw_printf("failed to restart reception\n\r");
}
}

void HAL_UART_ErrorCallback(UART_HandleTypeDef* h){
Caw_printf("UART error %i\n\r", h->ErrorCode);
}
21 changes: 21 additions & 0 deletions ll/uart.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include "stm32f7xx_hal.h"

typedef enum{
UART_Rx,
UART_Tx,
} UART_Direction;

typedef void (*U8_Callback)(uint8_t);

typedef struct{
UART_HandleTypeDef hUart;
U8_Callback cb_handler;
} Uart;

Uart* UART_init(Uart* self, UART_Direction dir, USART_TypeDef* instance, char* pin);

void UART_set_callback(Uart* self, U8_Callback callback);

void UART_send(Uart* self, uint8_t* data, size_t len);
57 changes: 38 additions & 19 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
#include "lib/flash.h" // Flash_clear_user_script()
#include "stm32f7xx_it.h" // CPU_count;

#include "lib/midi.h"
#include "ll/uart.h"

static Uart uart_rx;
static Uart uart_tx;
static Midi midi;

int main(void)
{
Expand All @@ -27,29 +33,35 @@ int main(void)
// Debugging
Debug_Pin_Init();
Debug_Pin_Set(0,1);
Debug_USART_Init(); // ignored in TRACE mode
// Debug_USART_Init(); // ignored in TRACE mode
// User-readable status led
// status_led_init();
status_led_init();
// status_led_fast(LED_SLOW); // slow blink until USB connection goes live
// status_led_set(1); // set status to ON to show sign of life straight away

printf("\n\nhi from crow!\n\r");

U_PrintNow();

// MIDI
// pass initialized uart handlers to midi system
MIDI_init(&midi, UART_init(&uart_tx, UART_Tx, UART8, "E1"));
// setup midi reception uart
UART_init(&uart_rx, UART_Rx, UART5, "B8");
// redirect uart interrupts to midi system
UART_set_callback(&uart_rx, MIDI_get_callback(&midi));

// Drivers
int max_timers = Timer_Init();
IO_Init( max_timers-2 ); // use second-last timer
IO_Start(); // must start IO before running lua init() script
events_init();
Metro_Init( max_timers-2 ); // reserve 2 timers for USB & ADC
// IO_Init( max_timers-2 ); // use second-last timer
// IO_Start(); // must start IO before running lua init() script
// events_init();
// Metro_Init( max_timers-2 ); // reserve 2 timers for USB & ADC
// clock_init( 100 ); // TODO how to pass it the timer?
Caw_Init( max_timers-1 ); // use last timer
CDC_clear_buffers();

// i2c_hw_pullups_init(); // enable GPIO for v1.1 hardware pullups
// ii_init( II_CROW );
Random_Init();
// Random_Init();

// REPL_init( Lua_Init() );

Expand All @@ -59,6 +71,7 @@ int main(void)
uint32_t last_tick = HAL_GetTick();
int saw = 0;
int g_state = 0;
int counter = 0;
while(1){
CPU_count++;

Expand All @@ -68,10 +81,14 @@ int main(void)
Debug_Pin_Set(1, g_state);
g_state ^= 1;
// Caw_printf("hi\n\r");
// Caw_printf("%i\n\r",counter++);
uint8_t midi_msg[3] = {0x90, 0x3c, 0x64};
MIDI_transmit(&midi, midi_msg, 3);
}

U_PrintNow();
Caw_try_receive();
// U_PrintNow();
Caw_try_receive(); // something is broken in the receiver :/
// prob something to do with the different chip?
// switch( Caw_try_receive() ){ // true on pressing 'enter'
// case C_repl: REPL_eval( Caw_get_read()
// , Caw_get_read_len()
Expand All @@ -90,14 +107,16 @@ int main(void)
// case C_loadFirst: REPL_default_script(); break;
// default: break; // 'C_none' does nothing
// }
Random_Update();
uint32_t time_now = HAL_GetTick(); // for running a 1ms-interval tick
if( last_tick != time_now ){ // called on 1ms interval
last_tick = time_now;
// clock_update(time_now);
status_led_tick(time_now);
}
event_next(); // check/execute single event
// Random_Update();

// uint32_t time_now = HAL_GetTick(); // for running a 1ms-interval tick
// if( last_tick != time_now ){ // called on 1ms interval
// last_tick = time_now;
// // clock_update(time_now);
// status_led_tick(time_now);
// }

// event_next(); // check/execute single event
// ii_leader_process();
Caw_send_queued();
}
Expand Down

0 comments on commit 649c2e2

Please sign in to comment.