Skip to content

Instantly share code, notes, and snippets.

@inajob
Created December 27, 2023 23:17
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 inajob/eea0d77adb8807662e5c3bd0a80da697 to your computer and use it in GitHub Desktop.
Save inajob/eea0d77adb8807662e5c3bd0a80da697 to your computer and use it in GitHub Desktop.
pianoboard.c
/*
* 2023-12-28 inajob
* Copyright (c) 2023 inajob
This software is released under the MIT License.
http://opensource.org/licenses/mit-license.php
This is based on https://github.com/cnlohr/ch32v003fun/tree/master/examples/i2c_oled
*/
// what type of OLED - uncomment just one
//#define SSD1306_64X32
//#define SSD1306_128X32
#define SSD1306_128X64
#include "ch32v003fun.h"
#include "ch32v003_GPIO_branchless.h"
#include <stdio.h>
#include "ssd1306_i2c.h"
#include "ssd1306.h"
#include "bomb.h"
#define TIM2_DEFAULT 0xff
#define SYSTICK_SR_CNTIF (1<<0)
#define SYSTICK_CTLR_STE (1<<0)
#define SYSTICK_CTLR_STIE (1<<1)
#define SYSTICK_CTLR_STCLK (1<<2)
#define SYSTICK_CTLR_STRE (1<<3)
#define SYSTICK_CTLR_SWIE (1<<31)
volatile uint32_t systick_cnt;
volatile uint32_t add = 0;
volatile uint32_t osc = 0; // 0 -> 255*8
volatile uint32_t delta = 0;
volatile uint32_t osc2 = 0; // 0 -> 255*8
volatile uint32_t delta2 = 0;
volatile uint32_t osc3 = 0; // 0 -> 255*8
volatile uint32_t delta3 = 0;
uint32_t tones[] = {81, 92, 97, 109, 122, 130, 146};
/*
* Start up the SysTick IRQ
*/
void systick_init(void)
{
/* disable default SysTick behavior */
SysTick->CTLR = 0;
/* enable the SysTick IRQ */
NVIC_EnableIRQ(SysTicK_IRQn);
/* Set the tick interval to 1ms for normal op */
SysTick->CMP = (FUNCONF_SYSTEM_CORE_CLOCK/1000)-1;
/* Start at zero */
SysTick->CNT = 0;
systick_cnt = 0;
/* Enable SysTick counter, IRQ, HCLK/1 */
SysTick->CTLR = SYSTICK_CTLR_STE | SYSTICK_CTLR_STIE |
SYSTICK_CTLR_STCLK;
}
/*
* SysTick ISR just counts ticks
* note - the __attribute__((interrupt)) syntax is crucial!
*/
void SysTick_Handler(void) __attribute__((interrupt));
void SysTick_Handler(void)
{
// move the compare further ahead in time.
// as a warning, if more than this length of time
// passes before triggering, you may miss your
// interrupt.
SysTick->CMP += (FUNCONF_SYSTEM_CORE_CLOCK/(11000));
/* clear IRQ */
SysTick->SR = 0;
/* update counter */
systick_cnt+=add;
osc += delta;
osc2 += delta2;
osc3 += delta3;
t2pwm_setpw(0, systick_cnt%255); // CH1
//t2pwm_setpw(1, (((osc>>3)&255 + (osc2>>3)&255) + (osc3>>3)&255) >> 1); // CH2 180° out-of-phase
t2pwm_setpw(1, ((((osc>>3&255))<128?0:255) + (((osc2>>3&255))<128?0:255) + (((osc3>>3)&255)<128?0:255)) >> 1); // CH2 180° out-of-phase
}
/*
* initialize TIM2 for PWM
*/
void t2pwm_init( void )
{
// Enable GPIOD and TIM2
RCC->APB2PCENR |= RCC_APB2Periph_GPIOD;
RCC->APB1PCENR |= RCC_APB1Periph_TIM2;
// PD4 is T2CH1, 10MHz Output alt func, push-pull
// GPIOD->CFGLR &= ~(0xf<<(4*4));
// GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*4);
// PD3 is T2CH2, 10MHz Output alt func, push-pull
GPIOD->CFGLR &= ~(0xf<<(4*3));
GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*3);
// Reset TIM2 to init all regs
RCC->APB1PRSTR |= RCC_APB1Periph_TIM2;
RCC->APB1PRSTR &= ~RCC_APB1Periph_TIM2;
// SMCFGR: default clk input is CK_INT
// set TIM2 clock prescaler divider
TIM2->PSC = 0x0000;
// set PWM total cycle width
TIM2->ATRLR = 255;
// for channel 1 and 2, let CCxS stay 00 (output), set OCxM to 110 (PWM I)
// enabling preload causes the new pulse width in compare capture register only to come into effect when UG bit in SWEVGR is set (= initiate update) (auto-clears)
TIM2->CHCTLR1 |= TIM_OC1M_2 | TIM_OC1M_1 | TIM_OC1PE | TIM_OC2M_2 | TIM_OC2M_1 | TIM_OC2PE;
// CTLR1: default is up, events generated, edge align
// enable auto-reload of preload
TIM2->CTLR1 |= TIM_ARPE;
// Enable Channel outputs, set default state (based on TIM2_DEFAULT)
TIM2->CCER |= TIM_CC1E | (TIM_CC1P & TIM2_DEFAULT);
TIM2->CCER |= TIM_CC2E | (TIM_CC2P & TIM2_DEFAULT);
// initialize counter
TIM2->SWEVGR |= TIM_UG;
// Enable TIM2
TIM2->CTLR1 |= TIM_CEN;
}
/*
* set timer channel PW
*/
void t2pwm_setpw(uint8_t chl, uint16_t width)
{
switch(chl&3)
{
case 0: TIM2->CH1CVR = width; break;
case 1: TIM2->CH2CVR = width; break;
}
//TIM2->SWEVGR |= TIM_UG; // load new value in compare capture register
}
// function prototype (declaration), definition in "ch32v003fun.c"
int mini_snprintf(char* buffer, unsigned int buffer_len, const char *fmt, ...);
int main()
{
// 48MHz internal clock
SystemInit();
systick_init();
t2pwm_init();
Delay_Ms( 100 );
printf("\r\r\n\ni2c_oled example\n\r");
// init i2c and oled
Delay_Ms( 100 ); // give OLED some more time
printf("initializing i2c oled...");
if(!ssd1306_i2c_init())
{
ssd1306_init();
printf("done.\n\r");
// Setup GPIO
GPIO_port_enable(GPIO_port_C);
GPIO_port_enable(GPIO_port_D);
// Input Pull Up
GPIO_pinMode(GPIOv_from_PORT_PIN(GPIO_port_C, 0), GPIO_pinMode_I_pullUp, GPIO_Speed_In);
GPIO_pinMode(GPIOv_from_PORT_PIN(GPIO_port_D, 0), GPIO_pinMode_I_pullUp, GPIO_Speed_In);
GPIO_pinMode(GPIOv_from_PORT_PIN(GPIO_port_D, 2), GPIO_pinMode_I_pullUp, GPIO_Speed_In);
GPIO_pinMode(GPIOv_from_PORT_PIN(GPIO_port_D, 4), GPIO_pinMode_I_pullUp, GPIO_Speed_In);
// Output
GPIO_pinMode(GPIOv_from_PORT_PIN(GPIO_port_C, 3), GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz);
GPIO_pinMode(GPIOv_from_PORT_PIN(GPIO_port_C, 4), GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz);
GPIO_pinMode(GPIOv_from_PORT_PIN(GPIO_port_C, 5), GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz);
GPIO_pinMode(GPIOv_from_PORT_PIN(GPIO_port_C, 6), GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz);
GPIO_pinMode(GPIOv_from_PORT_PIN(GPIO_port_C, 7), GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz);
GPIO_digitalWrite(GPIOv_from_PORT_PIN(GPIO_port_C, 3), high);
GPIO_digitalWrite(GPIOv_from_PORT_PIN(GPIO_port_C, 4), high);
GPIO_digitalWrite(GPIOv_from_PORT_PIN(GPIO_port_C, 5), high);
GPIO_digitalWrite(GPIOv_from_PORT_PIN(GPIO_port_C, 6), high);
GPIO_digitalWrite(GPIOv_from_PORT_PIN(GPIO_port_C, 7), high);
char buf[128];
char buf2[128];
int buttons[20];
int count = 0;
while(1)
{
GPIO_digitalWrite(GPIOv_from_PORT_PIN(GPIO_port_C, 3), low);
buttons[0] = !GPIO_digitalRead(GPIOv_from_PORT_PIN(GPIO_port_D, 2));
buttons[1] = !GPIO_digitalRead(GPIOv_from_PORT_PIN(GPIO_port_D, 4));
buttons[2] = !GPIO_digitalRead(GPIOv_from_PORT_PIN(GPIO_port_D, 0));
buttons[3] = !GPIO_digitalRead(GPIOv_from_PORT_PIN(GPIO_port_C, 0));
GPIO_digitalWrite(GPIOv_from_PORT_PIN(GPIO_port_C, 3), high);
GPIO_digitalWrite(GPIOv_from_PORT_PIN(GPIO_port_C, 4), low);
Delay_Ms(10);
buttons[4] = !GPIO_digitalRead(GPIOv_from_PORT_PIN(GPIO_port_D, 2));
buttons[5] = !GPIO_digitalRead(GPIOv_from_PORT_PIN(GPIO_port_D, 4));
buttons[7] = !GPIO_digitalRead(GPIOv_from_PORT_PIN(GPIO_port_C, 0)); //?!
buttons[6] = !GPIO_digitalRead(GPIOv_from_PORT_PIN(GPIO_port_D, 0)); //?!
GPIO_digitalWrite(GPIOv_from_PORT_PIN(GPIO_port_C, 4), high);
GPIO_digitalWrite(GPIOv_from_PORT_PIN(GPIO_port_C, 5), low);
Delay_Ms(10);
buttons[8] = !GPIO_digitalRead(GPIOv_from_PORT_PIN(GPIO_port_D, 2));
buttons[9] = !GPIO_digitalRead(GPIOv_from_PORT_PIN(GPIO_port_D, 4));
buttons[10] = !GPIO_digitalRead(GPIOv_from_PORT_PIN(GPIO_port_D, 0));
buttons[11] = !GPIO_digitalRead(GPIOv_from_PORT_PIN(GPIO_port_C, 0));
GPIO_digitalWrite(GPIOv_from_PORT_PIN(GPIO_port_C, 5), high);
GPIO_digitalWrite(GPIOv_from_PORT_PIN(GPIO_port_C, 6), low);
Delay_Ms(10);
buttons[12] = !GPIO_digitalRead(GPIOv_from_PORT_PIN(GPIO_port_D, 2));
buttons[13] = !GPIO_digitalRead(GPIOv_from_PORT_PIN(GPIO_port_D, 4));
buttons[14] = !GPIO_digitalRead(GPIOv_from_PORT_PIN(GPIO_port_D, 0));
buttons[15] = !GPIO_digitalRead(GPIOv_from_PORT_PIN(GPIO_port_C, 0));
GPIO_digitalWrite(GPIOv_from_PORT_PIN(GPIO_port_C, 6), high);
GPIO_digitalWrite(GPIOv_from_PORT_PIN(GPIO_port_C, 7), low);
Delay_Ms(10);
buttons[16] = !GPIO_digitalRead(GPIOv_from_PORT_PIN(GPIO_port_D, 2));
buttons[17] = !GPIO_digitalRead(GPIOv_from_PORT_PIN(GPIO_port_D, 4));
buttons[18] = !GPIO_digitalRead(GPIOv_from_PORT_PIN(GPIO_port_D, 0));
buttons[19] = !GPIO_digitalRead(GPIOv_from_PORT_PIN(GPIO_port_C, 0));
GPIO_digitalWrite(GPIOv_from_PORT_PIN(GPIO_port_C, 7), high);
uint32_t pdelta[64];
int index = 0;
pdelta[0] = pdelta[1] = pdelta[2] = 0;
if(buttons[4]){pdelta[index++] = tones[2];} // do
if(buttons[6]){pdelta[index++] = tones[3];}
if(buttons[8]){pdelta[index++] = tones[4];}
if(buttons[9]){pdelta[index++] = tones[5];}
if(buttons[11]){pdelta[index++] = tones[6];}
if(buttons[13]){pdelta[index++] = tones[0] << 1;}
if(buttons[15]){pdelta[index++] = tones[1] << 1;}
if(buttons[16]){pdelta[index++] = tones[2] << 1;}
if(buttons[17]){pdelta[index++] = tones[3] << 1;}
delta = pdelta[0];
delta2 = pdelta[1];
delta3 = pdelta[2];
// clear buffer
ssd1306_setbuf(0);
mini_snprintf(buf,128, "counter: %d", count);
ssd1306_drawstr(0,0, buf, 1);
for(int i = 0; i < 20; i ++){
ssd1306_drawstr(i*5,8, buttons[i]?"#":"-", 1);
}
ssd1306_drawstr(0,16, "PianoBoard", 1);
ssd1306_drawstr(0,24, "CH32V003", 1);
ssd1306_refresh();
Delay_Ms(10);
count ++;
}
}
else
printf("failed.\n\r");
printf("Stuck here forever...\n\r");
while(1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment