diff --git a/firmware/core/i2c/i2c.h b/firmware/core/i2c/i2c.h index 6a9b5a6..08689fa 100644 --- a/firmware/core/i2c/i2c.h +++ b/firmware/core/i2c/i2c.h @@ -71,11 +71,12 @@ extern volatile uint8_t I2CMasterBuffer[I2C_BUFSIZE]; extern volatile uint8_t I2CSlaveBuffer[I2C_BUFSIZE]; -extern volatile uint32_t I2CReadLength, I2CWriteLength; +extern volatile uint32_t I2CReadLength; +extern volatile uint32_t I2CWriteLength; extern void I2C_IRQHandler( void ); -extern uint32_t i2cInit( uint32_t I2cMode ); -extern uint32_t i2cEngine( void ); +uint32_t i2cInit( uint32_t I2cMode ); +uint32_t i2cEngine( void ); #endif /* end __I2C_H */ /**************************************************************************** diff --git a/firmware/core/timer32/timer32.c b/firmware/core/timer32/timer32.c index 61edf16..3644ef8 100644 --- a/firmware/core/timer32/timer32.c +++ b/firmware/core/timer32/timer32.c @@ -124,22 +124,26 @@ void timer32Delay(uint8_t timerNum, uint32_t delay) } -//we do this in applications -#if 0 /**************************************************************************/ /*! @brief Interrupt handler for 32-bit timer 0 */ /**************************************************************************/ +uint32_t timer32Callback0; + void TIMER32_0_IRQHandler(void) { + +void (*callback)(void); + /* Clear the interrupt flag */ TMR_TMR32B0IR = TMR_TMR32B0IR_MR0; /* If you wish to perform some action after each timer 'tick' (such as incrementing a counter variable) you can do so here */ timer32_0_counter++; - + callback=(void (*)(void)) ((uint32_t)(timer32Callback0) | 1); // Enable Thumb mode! + callback(); return; } @@ -159,7 +163,6 @@ void TIMER32_1_IRQHandler(void) return; } -#endif /**************************************************************************/ /*! diff --git a/firmware/core/timer32/timer32.h b/firmware/core/timer32/timer32.h index b7135a8..bac0479 100644 --- a/firmware/core/timer32/timer32.h +++ b/firmware/core/timer32/timer32.h @@ -54,6 +54,7 @@ #define TIMER32_DELAY_1MS (10) // 1mS delay = 10 ticks #define TIMER32_DELAY_1S (10000) // 1S delay = 10000 ticks +extern uint32_t timer32Callback0; void TIMER32_0_IRQHandler(void); void TIMER32_1_IRQHandler(void); diff --git a/firmware/l0dable/EXPORTS b/firmware/l0dable/EXPORTS index 66917af..87267c0 100644 --- a/firmware/l0dable/EXPORTS +++ b/firmware/l0dable/EXPORTS @@ -116,3 +116,11 @@ uint8ptouint32 #o_set_shader #o_identity #o_transform +#I2C +I2CMasterBuffer +I2CSlaveBuffer +I2CWriteLength +I2CReadLength +i2cEngine +i2cInit +timer32Callback0 diff --git a/firmware/l0dable/worksh.c b/firmware/l0dable/worksh.c index 52a6008..3d8341f 100644 --- a/firmware/l0dable/worksh.c +++ b/firmware/l0dable/worksh.c @@ -14,6 +14,7 @@ #include #include +#include #include "basic/basic.h" #include "basic/config.h" @@ -21,88 +22,73 @@ #include "lcd/render.h" #include "lcd/print.h" +#include "core/i2c/i2c.h" +#include "core/timer32/timer32.h" #include "usetable.h" -// Liberated from ARM Cortex M3 CMSIS core_cm3.h -// The processor definition headers for R0ket are incomplete :-/ +//I2C address: (C0-CF) +#define LK_I2C_WRITE 0xCE +#define LK_I2C_READ 0xCF -#define __I -#define __IO volatile +#define LK_I2C_CR_INPUT0 0x00 +#define LK_I2C_CR_INPUT1 0x01 +#define LK_I2C_CR_PSC0 0x02 +#define LK_I2C_CR_PWM0 0x03 +#define LK_I2C_CR_PSC1 0x04 +#define LK_I2C_CR_PWM1 0x05 +#define LK_I2C_CR_LS0 0x06 +#define LK_I2C_CR_LS1 0x07 +#define LK_I2C_CR_LS2 0x08 +#define LK_I2C_CR_LS3 0x09 -typedef struct { - __I uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPU ID Base Register */ - __IO uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control State Register */ - __IO uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ - __IO uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt / Reset Control Register */ - __IO uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ - __IO uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ - __IO uint8_t SHP[12]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */ - __IO uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ - __IO uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */ - __IO uint32_t HFSR; /*!< Offset: 0x02C (R/W) Hard Fault Status Register */ - __IO uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */ - __IO uint32_t MMFAR; /*!< Offset: 0x034 (R/W) Mem Manage Address Register */ - __IO uint32_t BFAR; /*!< Offset: 0x038 (R/W) Bus Fault Address Register */ - __IO uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */ - __I uint32_t PFR[2]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */ - __I uint32_t DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */ - __I uint32_t ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */ - __I uint32_t MMFR[4]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */ - __I uint32_t ISAR[5]; /*!< Offset: 0x060 (R/ ) ISA Feature Register */ -} SCB_Type; +#define LK_I2C_LS_OFF 0x00 +#define LK_I2C_LS_ON 0x01 +#define LK_I2C_LS_PWM0 0x02 +#define LK_I2C_LS_PWM1 0x03 -#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ -#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ -#define SCB ((SCB_Type *) SCB_BASE) /*!< SCB configuration struct */ +#define LK_PIEZO RB_SPI_SS3 -uint32_t VectorTableInRAM[73] __attribute__ ((aligned(1024))); // VTOR needs 1024 Byte alignment, see UM10375.PDF -void (*orig_handler)(void); // original EINT3 handler +uint8_t lkEnabled = 0; +uint8_t lk_button_mode = 0x00; -void TIMER32_0_IRQHandler(void); +uint8_t lk_ls0 = 0x00; +uint8_t lk_ls1 = 0x00; +uint8_t lk_ls2 = 0x00; +uint8_t lk_ls3 = 0x00; -// Remember: ram() must be the first function, place all other code AFTER -// because the Implementer seem not to know how to use section attributes +uint8_t lk_in0 = 0x00; +uint8_t lk_in1 = 0x00; +uint16_t lk_ticks = 0x0000; +uint8_t lk_piezo_toggle = 0x00; + +static void init_lilakit(void); +static void tick_lilakit(void); static void mainloop(); +void handler(void); void ram(void) { - uint8_t button; - uint32_t LEDs; - - // populate my Vector table - memcpy(VectorTableInRAM, 0, sizeof(VectorTableInRAM)); - orig_handler = (void*) VectorTableInRAM[TIMER_32_0_IRQn + 16]; - VectorTableInRAM[TIMER_32_0_IRQn + 16] = (uint32_t) &TIMER32_0_IRQHandler; - // HACK: use RAM vector table to implement own IRQ handler - SCB->VTOR = (uint32_t) &VectorTableInRAM[0]; - // TODO add DMB() here, as VTOR updates are NOT effective immediately - // - NVIC_EnableIRQ(TIMER_32_0_IRQn); + timer32Callback0 = handler; /* Enable the clock for CT32B0 */ SCB_SYSAHBCLKCTRL |= (SCB_SYSAHBCLKCTRL_CT32B0); TMR_TMR32B0MR0 = (72E6/5E3)/2; TMR_TMR32B0MCR = (TMR_TMR32B0MCR_MR0_INT_ENABLED | TMR_TMR32B0MCR_MR0_RESET_ENABLED); + NVIC_EnableIRQ(TIMER_32_0_IRQn); TMR_TMR32B0TCR = TMR_TMR32B0TCR_COUNTERENABLE_ENABLED; - + init_lilakit(); mainloop(); - NVIC_DisableIRQ(TIMER_32_0_IRQn); + NVIC_DisableIRQ(TIMER_32_0_IRQn); TMR_TMR32B0TCR = TMR_TMR32B0TCR_COUNTERENABLE_DISABLED; - // restore VTOR - SCB->VTOR = 0; - //TODO DMB(); Cortex Manual suggests DMB after setting VTOR - // not really needed in this case } -void TIMER32_0_IRQHandler(void) +void handler(void) { - TMR_TMR32B0IR = TMR_TMR32B0IR_MR0; static int time=0; if (time==0){time=1;} else {time=0;} - gpioSetValue (RB_LED2, time); - gpioSetValue (RB_SPI_SS3, time); + gpioSetValue (LK_PIEZO, time); } static void mainloop(void) { @@ -126,7 +112,125 @@ static void mainloop(void) { while(getInputRaw()==BTN_NONE){ delayms_queue_plus(10,0); }; + tick_lilakit(); return; } +static uint32_t lkSetI2C(uint8_t cr, uint8_t value) { + I2CMasterBuffer[0] = LK_I2C_WRITE; + I2CMasterBuffer[1] = cr; + I2CMasterBuffer[2] = value; + I2CWriteLength = 3; + I2CReadLength = 0; + return i2cEngine(); +} + +static uint8_t lkGetI2C(uint8_t cr) { + I2CMasterBuffer[0] = LK_I2C_WRITE; + I2CMasterBuffer[1] = cr; + I2CWriteLength = 2; + I2CReadLength = 0; + i2cEngine(); + + I2CMasterBuffer[0] = LK_I2C_READ; + I2CMasterBuffer[1] = cr; + I2CWriteLength = 2; + I2CReadLength = 1; + i2cEngine(); + return I2CSlaveBuffer[0]; +} + +static void lkUpdateI2C() { + lkSetI2C(LK_I2C_CR_LS0, lk_ls0); + lkSetI2C(LK_I2C_CR_LS1, lk_ls1); + lkSetI2C(LK_I2C_CR_LS2, lk_ls2); + lkSetI2C(LK_I2C_CR_LS3, lk_ls3); +} + +static void lkReadI2C() { + lk_in0 = lkGetI2C(LK_I2C_CR_INPUT0); + lk_in1 = lkGetI2C(LK_I2C_CR_INPUT1); +} + +static void tick_lilakit(void) +{ // every 10ms + if (lkEnabled == 0) { + return; + } + + lk_ticks++; + + if (lk_ticks % 10 == 0) { + lkReadI2C(); + } + + if ((lk_in0 & 0x02) == 0 && lk_button_mode == 0) { + lk_ticks = 0; + lk_button_mode = 1; + + lk_ls1 = 0; + lk_ls1 |= LK_I2C_LS_ON << 4; + lk_ls1 |= LK_I2C_LS_ON << 6; + lkUpdateI2C(); + } + + if (lk_button_mode == 1 && lk_ticks > 0xFF) { + lk_button_mode = 0; + lk_ls1 = 0; + lk_ls1 |= LK_I2C_LS_PWM0 << 4; + lk_ls1 |= LK_I2C_LS_PWM1 << 6; + lkUpdateI2C(); + } + +} + +static void init_lilakit(void) { + + i2cInit(I2CMASTER); // Init I2C + + lkEnabled = (lkSetI2C(LK_I2C_CR_LS0, LK_I2C_LS_OFF << 0) == I2CSTATE_ACK); // probe i2c + if (lkEnabled == 0) { + return; + } + + // All LEDs off + lkSetI2C(LK_I2C_CR_LS0, LK_I2C_LS_OFF << 0); + lkSetI2C(LK_I2C_CR_LS0, LK_I2C_LS_OFF << 2); + lkSetI2C(LK_I2C_CR_LS0, LK_I2C_LS_OFF << 4); + lkSetI2C(LK_I2C_CR_LS0, LK_I2C_LS_OFF << 6); + lkSetI2C(LK_I2C_CR_LS1, LK_I2C_LS_OFF << 0); + lkSetI2C(LK_I2C_CR_LS1, LK_I2C_LS_OFF << 2); + lkSetI2C(LK_I2C_CR_LS1, LK_I2C_LS_OFF << 4); + lkSetI2C(LK_I2C_CR_LS1, LK_I2C_LS_OFF << 6); + lkSetI2C(LK_I2C_CR_LS2, LK_I2C_LS_OFF << 0); + lkSetI2C(LK_I2C_CR_LS2, LK_I2C_LS_OFF << 2); + lkSetI2C(LK_I2C_CR_LS2, LK_I2C_LS_OFF << 4); + lkSetI2C(LK_I2C_CR_LS2, LK_I2C_LS_OFF << 6); + lkSetI2C(LK_I2C_CR_LS3, LK_I2C_LS_OFF << 0); + lkSetI2C(LK_I2C_CR_LS3, LK_I2C_LS_OFF << 2); + lkSetI2C(LK_I2C_CR_LS3, LK_I2C_LS_OFF << 4); + lkSetI2C(LK_I2C_CR_LS3, LK_I2C_LS_OFF << 6); + + // All PWMs off + lkSetI2C(LK_I2C_CR_PSC0, 0x00); + lkSetI2C(LK_I2C_CR_PWM0, 0x00); + lkSetI2C(LK_I2C_CR_PSC1, 0x00); + lkSetI2C(LK_I2C_CR_PWM1, 0x00); + + // Prepare SS + gpioSetDir(LK_PIEZO, gpioDirection_Output); + gpioSetValue(LK_PIEZO, 1); + + + // Prepare blinking + lkSetI2C(LK_I2C_CR_PSC0, 0x23); + lkSetI2C(LK_I2C_CR_PWM0, 0x66); + lkSetI2C(LK_I2C_CR_PSC1, 0x75); + lkSetI2C(LK_I2C_CR_PWM1, 0x12); + + // Enable both LEDs + lk_ls1 |= LK_I2C_LS_PWM0 << 4; + lk_ls1 |= LK_I2C_LS_PWM1 << 6; + lkSetI2C(LK_I2C_CR_LS1, lk_ls1); +}