From 30680c6eb396a2bb06928afd69edae9908ac84fb Mon Sep 17 00:00:00 2001
From: patrickmt <40182064+patrickmt@users.noreply.github.com>
Date: Wed, 29 Aug 2018 15:07:52 -0400
Subject: Massdrop keyboard support (#3780)
* Massdrop SAMD51
Massdrop SAMD51 keyboards initial project upload
* Removing relocated files
Removing files that were relocated and not deleted from previous location
* LED queue fix and cleaning
Cleaned some white space or comments.
Fix for LED I2C command queue.
Cleaned up interrupts.
Added debug function for printing numbers to scope through m15 line.
* Factory programmed serial usage
Ability to use factory programmed serial in hub and keyboard usb descriptors
* USB serial number and bugfix
Added support for factory programmed serial and usage.
Incorporated bootloader's conditional compiling to align project closer.
Fixed issue when USB device attempted to send before enabled.
General white space and comment cleanup.
* Project cleanup
Cleaned up project in terms of white space, commented code, and unecessary files.
NKRO keyboard is now using correct setreport although KBD was fine to use.
Fixed broken linkage to __xprintf for serial debug statements.
* Fix for extra keys
Fixed possible USB hang on extra keys report set missing
* I2C cleanup
I2C cleanup and file renames necessary for master branch merge
* Boot tracing and clocks cleanup
Added optional boot debug trace mode through debug LED codes.
General clock code cleanup.
* Relocate ARM/Atmel headers
Moved ARM/Atmel header folder from drivers to lib and made necessary makefile changes.
* Pull request changes
Pull request changes
* Keymap and compile flag fix
Keymap fix for momentary layer.
Potential compile flag fix for Travis CI failure.
* va_list include fix
Fix for va_list compile failure
* Include file case fixes
Fixes for include files with incorrect case
* ctrl and alt67 keyboard readme
Added ctrl and alt67 keyboard readme files
---
tmk_core/protocol/arm_atsam/i2c_master.c | 585 +++++++++++++++++++++++++++++++
1 file changed, 585 insertions(+)
create mode 100644 tmk_core/protocol/arm_atsam/i2c_master.c
(limited to 'tmk_core/protocol/arm_atsam/i2c_master.c')
diff --git a/tmk_core/protocol/arm_atsam/i2c_master.c b/tmk_core/protocol/arm_atsam/i2c_master.c
new file mode 100644
index 0000000000..bbe909e9bb
--- /dev/null
+++ b/tmk_core/protocol/arm_atsam/i2c_master.c
@@ -0,0 +1,585 @@
+/*
+Copyright 2018 Massdrop Inc.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+#include "arm_atsam_protocol.h"
+
+#ifndef MD_BOOTLOADER
+
+#include
+
+//From keyboard
+#include "config.h"
+#include "config_led.h"
+#include "matrix.h"
+
+#define I2C_LED_USE_DMA 1 //Set 1 to use background DMA transfers for leds, Set 0 to use inline software transfers
+
+static uint8_t i2c_led_q[I2C_Q_SIZE]; //I2C queue circular buffer
+static uint8_t i2c_led_q_s; //Start of circular buffer
+static uint8_t i2c_led_q_e; //End of circular buffer
+static uint8_t i2c_led_q_full; //Queue full counter for reset
+
+static uint8_t dma_sendbuf[I2C_DMA_MAX_SEND]; //Data being written to I2C
+
+volatile uint8_t i2c_led_q_running;
+
+#endif //MD_BOOTLOADER
+
+void i2c0_init(void)
+{
+ DBGC(DC_I2C0_INIT_BEGIN);
+
+ CLK_set_i2c0_freq(CHAN_SERCOM_I2C0, FREQ_I2C0_DEFAULT);
+
+ //MCU
+ PORT->Group[0].PMUX[4].bit.PMUXE = 2;
+ PORT->Group[0].PMUX[4].bit.PMUXO = 2;
+ PORT->Group[0].PINCFG[8].bit.PMUXEN = 1;
+ PORT->Group[0].PINCFG[9].bit.PMUXEN = 1;
+
+ //I2C
+ //Note: SW Reset handled in CLK_set_i2c0_freq clks.c
+
+ SERCOM0->I2CM.CTRLA.bit.MODE = 5; //Set master mode
+
+ SERCOM0->I2CM.CTRLA.bit.SPEED = 0; //Set to 1 for Fast-mode Plus (FM+) up to 1 MHz
+ SERCOM0->I2CM.CTRLA.bit.RUNSTDBY = 1; //Enabled
+
+ SERCOM0->I2CM.CTRLA.bit.ENABLE = 1; //Enable the device
+ while (SERCOM0->I2CM.SYNCBUSY.bit.ENABLE) { DBGC(DC_I2C0_INIT_SYNC_ENABLING); } //Wait for SYNCBUSY.ENABLE to clear
+
+ SERCOM0->I2CM.STATUS.bit.BUSSTATE = 1; //Force into IDLE state
+ while (SERCOM0->I2CM.SYNCBUSY.bit.SYSOP) { DBGC(DC_I2C0_INIT_SYNC_SYSOP); }
+ while (SERCOM0->I2CM.STATUS.bit.BUSSTATE != 1) { DBGC(DC_I2C0_INIT_WAIT_IDLE); } //Wait while not idle
+
+ DBGC(DC_I2C0_INIT_COMPLETE);
+}
+
+uint8_t i2c0_start(uint8_t address)
+{
+ SERCOM0->I2CM.ADDR.bit.ADDR = address;
+ while (SERCOM0->I2CM.SYNCBUSY.bit.SYSOP) {}
+ while (SERCOM0->I2CM.INTFLAG.bit.MB == 0) {}
+ while (SERCOM0->I2CM.STATUS.bit.RXNACK) {}
+
+ return 1;
+}
+
+uint8_t i2c0_transmit(uint8_t address, uint8_t *data, uint16_t length, uint16_t timeout)
+{
+ if (!length) return 0;
+
+ i2c0_start(address);
+
+ while (length)
+ {
+ SERCOM0->I2CM.DATA.bit.DATA = *data;
+ while (SERCOM0->I2CM.INTFLAG.bit.MB == 0) {}
+ while (SERCOM0->I2CM.STATUS.bit.RXNACK) {}
+
+ data++;
+ length--;
+ }
+
+ i2c0_stop();
+
+ return 1;
+}
+
+void i2c0_stop(void)
+{
+ if (SERCOM0->I2CM.STATUS.bit.CLKHOLD || SERCOM0->I2CM.INTFLAG.bit.MB == 1 || SERCOM0->I2CM.STATUS.bit.BUSSTATE != 1)
+ {
+ SERCOM0->I2CM.CTRLB.bit.CMD = 3;
+ while (SERCOM0->I2CM.SYNCBUSY.bit.SYSOP);
+ while (SERCOM0->I2CM.STATUS.bit.CLKHOLD);
+ while (SERCOM0->I2CM.INTFLAG.bit.MB);
+ while (SERCOM0->I2CM.STATUS.bit.BUSSTATE != 1);
+ }
+}
+
+#ifndef MD_BOOTLOADER
+void i2c1_init(void)
+{
+ DBGC(DC_I2C1_INIT_BEGIN);
+
+ CLK_set_i2c1_freq(CHAN_SERCOM_I2C1, FREQ_I2C1_DEFAULT);
+
+ /* MCU */
+ PORT->Group[0].PMUX[8].bit.PMUXE = 2;
+ PORT->Group[0].PMUX[8].bit.PMUXO = 2;
+ PORT->Group[0].PINCFG[16].bit.PMUXEN = 1;
+ PORT->Group[0].PINCFG[17].bit.PMUXEN = 1;
+
+ /* I2C */
+ //Note: SW Reset handled in CLK_set_i2c1_freq clks.c
+
+ SERCOM1->I2CM.CTRLA.bit.MODE = 5; //MODE: Set master mode (No sync)
+ SERCOM1->I2CM.CTRLA.bit.SPEED = 1; //SPEED: Fm+ up to 1MHz (No sync)
+ SERCOM1->I2CM.CTRLA.bit.RUNSTDBY = 1; //RUNSTBY: Enabled (No sync)
+
+ SERCOM1->I2CM.CTRLB.bit.SMEN = 1; //SMEN: Smart mode enabled (For DMA)(No sync)
+
+ NVIC_EnableIRQ(SERCOM1_0_IRQn);
+ SERCOM1->I2CM.INTENSET.bit.ERROR = 1;
+
+ SERCOM1->I2CM.CTRLA.bit.ENABLE = 1; //ENABLE: Enable the device (sync SYNCBUSY.ENABLE)
+ while (SERCOM1->I2CM.SYNCBUSY.bit.ENABLE) { DBGC(DC_I2C1_INIT_SYNC_ENABLING); } //Wait for SYNCBUSY.ENABLE to clear
+
+ SERCOM1->I2CM.STATUS.bit.BUSSTATE = 1; //BUSSTATE: Force into IDLE state (sync SYNCBUSY.SYSOP)
+ while (SERCOM1->I2CM.SYNCBUSY.bit.SYSOP) { DBGC(DC_I2C1_INIT_SYNC_SYSOP); }
+ while (SERCOM1->I2CM.STATUS.bit.BUSSTATE != 1) { DBGC(DC_I2C1_INIT_WAIT_IDLE); } //Wait while not idle
+
+ DBGC(DC_I2C1_INIT_COMPLETE);
+}
+
+uint8_t i2c1_start(uint8_t address)
+{
+ SERCOM1->I2CM.ADDR.bit.ADDR = address;
+ while (SERCOM1->I2CM.SYNCBUSY.bit.SYSOP) {}
+ while (SERCOM1->I2CM.INTFLAG.bit.MB == 0) {}
+ while (SERCOM1->I2CM.STATUS.bit.RXNACK) {}
+
+ return 1;
+}
+
+uint8_t i2c1_transmit(uint8_t address, uint8_t *data, uint16_t length, uint16_t timeout)
+{
+ if (!length) return 0;
+
+ i2c1_start(address);
+
+ while (length)
+ {
+ SERCOM1->I2CM.DATA.bit.DATA = *data;
+ while (SERCOM1->I2CM.INTFLAG.bit.MB == 0) {}
+ while (SERCOM1->I2CM.STATUS.bit.RXNACK) {}
+
+ data++;
+ length--;
+ }
+
+ i2c1_stop();
+
+ return 1;
+}
+
+void i2c1_stop(void)
+{
+ if (SERCOM1->I2CM.STATUS.bit.CLKHOLD || SERCOM1->I2CM.INTFLAG.bit.MB == 1 || SERCOM1->I2CM.STATUS.bit.BUSSTATE != 1)
+ {
+ SERCOM1->I2CM.CTRLB.bit.CMD = 3;
+ while (SERCOM1->I2CM.SYNCBUSY.bit.SYSOP);
+ while (SERCOM1->I2CM.STATUS.bit.CLKHOLD);
+ while (SERCOM1->I2CM.INTFLAG.bit.MB);
+ while (SERCOM1->I2CM.STATUS.bit.BUSSTATE != 1);
+ }
+}
+
+void i2c_led_send_CRWL(uint8_t drvid)
+{
+ uint8_t i2cdata[] = { ISSI3733_CMDRWL, ISSI3733_CMDRWL_WRITE_ENABLE_ONCE };
+ i2c1_transmit(issidrv[drvid].addr, i2cdata, sizeof(i2cdata), 0);
+}
+
+void i2c_led_select_page(uint8_t drvid, uint8_t pageno)
+{
+ uint8_t i2cdata[] = { ISSI3733_CMDR, pageno };
+ i2c1_transmit(issidrv[drvid].addr, i2cdata, sizeof(i2cdata), 0);
+}
+
+void i2c_led_send_GCR(uint8_t drvid)
+{
+ uint8_t i2cdata[] = { ISSI3733_GCCR, 0x00 };
+
+ if (gcr_actual > LED_GCR_MAX) gcr_actual = LED_GCR_MAX;
+ i2cdata[1] = gcr_actual;
+
+ i2c1_transmit(issidrv[drvid].addr, i2cdata, sizeof(i2cdata), 0);
+}
+
+void i2c_led_send_onoff(uint8_t drvid)
+{
+#if I2C_LED_USE_DMA != 1
+ if (!i2c_led_q_running)
+ {
+#endif
+ i2c_led_send_CRWL(drvid);
+ i2c_led_select_page(drvid, 0);
+#if I2C_LED_USE_DMA != 1
+ }
+#endif
+
+ *issidrv[drvid].onoff = 0; //Force start location offset to zero
+ i2c1_transmit(issidrv[drvid].addr, issidrv[drvid].onoff, ISSI3733_PG0_BYTES, 0);
+}
+
+void i2c_led_send_mode_op_gcr(uint8_t drvid, uint8_t mode, uint8_t operation)
+{
+ uint8_t i2cdata[] = { ISSI3733_CR, mode | operation, gcr_actual};
+ i2c1_transmit(issidrv[drvid].addr, i2cdata, sizeof(i2cdata), 0);
+}
+
+void i2c_led_send_pur_pdr(uint8_t drvid, uint8_t pur, uint8_t pdr)
+{
+ uint8_t i2cdata[] = { ISSI3733_SWYR_PUR, pur, pdr };
+
+ i2c1_transmit(issidrv[drvid].addr, i2cdata, sizeof(i2cdata), 0);
+}
+
+void i2c_led_send_pwm(uint8_t drvid)
+{
+#if I2C_LED_USE_DMA != 1
+ if (!i2c_led_q_running)
+ {
+#endif
+ i2c_led_send_CRWL(drvid);
+ i2c_led_select_page(drvid, 0);
+#if I2C_LED_USE_DMA != 1
+ }
+#endif
+
+ *issidrv[drvid].pwm = 0; //Force start location offset to zero
+ i2c1_transmit(issidrv[drvid].addr, issidrv[drvid].pwm, ISSI3733_PG1_BYTES, 0);
+}
+
+uint8_t I2C3733_Init_Control(void)
+{
+ DBGC(DC_I2C3733_INIT_CONTROL_BEGIN);
+
+ srdata.bit.SDB_N = 1;
+ SPI_WriteSRData();
+
+ CLK_delay_ms(1);
+
+ srdata.bit.IRST = 0;
+ SPI_WriteSRData();
+
+ CLK_delay_ms(1);
+
+ DBGC(DC_I2C3733_INIT_CONTROL_COMPLETE);
+
+ return 1;
+}
+
+uint8_t I2C3733_Init_Drivers(void)
+{
+ DBGC(DC_I2C3733_INIT_DRIVERS_BEGIN);
+
+ gcr_actual = ISSI3733_GCR_DEFAULT;
+ gcr_actual_last = gcr_actual;
+
+ if (gcr_actual > LED_GCR_MAX) gcr_actual = LED_GCR_MAX;
+ gcr_desired = gcr_actual;
+
+ //Set up master device
+ i2c_led_send_CRWL(0);
+ i2c_led_select_page(0, 3);
+ i2c_led_send_mode_op_gcr(0, ISSI3733_CR_SYNC_MASTER, ISSI3733_CR_SSD_NORMAL);
+
+ //Set up slave device
+ i2c_led_send_CRWL(1);
+ i2c_led_select_page(1, 3);
+ i2c_led_send_mode_op_gcr(1, ISSI3733_CR_SYNC_SLAVE, ISSI3733_CR_SSD_NORMAL);
+
+ i2c_led_send_CRWL(0);
+ i2c_led_select_page(0, 3);
+ i2c_led_send_pur_pdr(0, ISSI3733_SWYR_PUR_8000, ISSI3733_CSXR_PDR_8000);
+
+ i2c_led_send_CRWL(1);
+ i2c_led_select_page(1, 3);
+ i2c_led_send_pur_pdr(1, ISSI3733_SWYR_PUR_8000, ISSI3733_CSXR_PDR_8000);
+
+ DBGC(DC_I2C3733_INIT_DRIVERS_COMPLETE);
+
+ return 1;
+}
+
+void I2C_DMAC_LED_Init(void)
+{
+ Dmac *dmac = DMAC;
+
+ DBGC(DC_I2C_DMAC_LED_INIT_BEGIN);
+
+ //Disable device
+ dmac->CTRL.bit.DMAENABLE = 0; //Disable DMAC
+ while (dmac->CTRL.bit.DMAENABLE) {} //Wait for disabled state in case of ongoing transfers
+ dmac->CTRL.bit.SWRST = 1; //Software Reset DMAC
+ while (dmac->CTRL.bit.SWRST) {} //Wait for software reset to complete
+
+ //Configure device
+ dmac->BASEADDR.reg = (uint32_t)&dmac_desc; //Set descriptor base address
+ dmac->WRBADDR.reg = (uint32_t)&dmac_desc_wb; //Set descriptor write back address
+ dmac->CTRL.reg |= 0x0f00; //Handle all priorities (LVL0-3)
+
+ //Disable channel
+ dmac->Channel[0].CHCTRLA.bit.ENABLE = 0; //Disable the channel
+ while (dmac->Channel[0].CHCTRLA.bit.ENABLE) {} //Wait for disabled state in case of ongoing transfers
+ dmac->Channel[0].CHCTRLA.bit.SWRST = 1; //Software Reset the channel
+ while (dmac->Channel[0].CHCTRLA.bit.SWRST) {} //Wait for software reset to complete
+
+ //Configure channel
+ dmac->Channel[0].CHCTRLA.bit.THRESHOLD = 0; //1BEAT
+ dmac->Channel[0].CHCTRLA.bit.BURSTLEN = 0; //SINGLE
+ dmac->Channel[0].CHCTRLA.bit.TRIGACT = 2; //BURST
+ dmac->Channel[0].CHCTRLA.bit.TRIGSRC = SERCOM1_DMAC_ID_TX; //Trigger source
+ dmac->Channel[0].CHCTRLA.bit.RUNSTDBY = 1; //Run in standby
+
+ NVIC_EnableIRQ(DMAC_0_IRQn);
+ dmac->Channel[0].CHINTENSET.bit.TCMPL = 1;
+ dmac->Channel[0].CHINTENSET.bit.TERR = 1;
+
+ //Enable device
+ dmac->CTRL.bit.DMAENABLE = 1; //Enable DMAC
+ while (dmac->CTRL.bit.DMAENABLE == 0) {} //Wait for enable state
+
+ DBGC(DC_I2C_DMAC_LED_INIT_COMPLETE);
+}
+
+//state = 1 enable
+//state = 0 disable
+void I2C3733_Control_Set(uint8_t state)
+{
+ DBGC(DC_I2C3733_CONTROL_SET_BEGIN);
+
+ srdata.bit.SDB_N = (state == 1 ? 1 : 0);
+ SPI_WriteSRData();
+
+ DBGC(DC_I2C3733_CONTROL_SET_COMPLETE);
+}
+
+void i2c_led_desc_defaults(void)
+{
+ dmac_desc.BTCTRL.bit.STEPSIZE = 0; //SRCINC used in favor for auto 1 inc
+ dmac_desc.BTCTRL.bit.STEPSEL = 0; //SRCINC used in favor for auto 1 inc
+ dmac_desc.BTCTRL.bit.DSTINC = 0; //The Destination Address Increment is disabled
+ dmac_desc.BTCTRL.bit.SRCINC = 1; //The Source Address Increment is enabled (Inc by 1)
+ dmac_desc.BTCTRL.bit.BEATSIZE = 0; //8-bit bus transfer
+ dmac_desc.BTCTRL.bit.BLOCKACT = 0; //Channel will be disabled if it is the last block transfer in the transaction
+ dmac_desc.BTCTRL.bit.EVOSEL = 0; //Event generation disabled
+ dmac_desc.BTCTRL.bit.VALID = 1; //Set dmac valid
+}
+
+void i2c_led_prepare_send_dma(uint8_t *data, uint8_t len)
+{
+ i2c_led_desc_defaults();
+
+ dmac_desc.BTCNT.reg = len;
+ dmac_desc.SRCADDR.reg = (uint32_t)data + len;
+ dmac_desc.DSTADDR.reg = (uint32_t)&SERCOM1->I2CM.DATA.reg;
+ dmac_desc.DESCADDR.reg = 0;
+}
+
+void i2c_led_begin_dma(uint8_t drvid)
+{
+ DMAC->Channel[0].CHCTRLA.bit.ENABLE = 1; //Enable the channel
+
+ SERCOM1->I2CM.ADDR.reg = (dmac_desc.BTCNT.reg << 16) | 0x2000 | issidrv[drvid].addr; //Begin transfer
+}
+
+void i2c_led_send_CRWL_dma(uint8_t drvid)
+{
+ *(dma_sendbuf+0) = ISSI3733_CMDRWL;
+ *(dma_sendbuf+1) = ISSI3733_CMDRWL_WRITE_ENABLE_ONCE;
+ i2c_led_prepare_send_dma(dma_sendbuf, 2);
+
+ i2c_led_begin_dma(drvid);
+}
+
+void i2c_led_select_page_dma(uint8_t drvid, uint8_t pageno)
+{
+ *(dma_sendbuf+0) = ISSI3733_CMDR;
+ *(dma_sendbuf+1) = pageno;
+ i2c_led_prepare_send_dma(dma_sendbuf, 2);
+
+ i2c_led_begin_dma(drvid);
+}
+
+void i2c_led_send_GCR_dma(uint8_t drvid)
+{
+ *(dma_sendbuf+0) = ISSI3733_GCCR;
+ *(dma_sendbuf+1) = gcr_actual;
+ i2c_led_prepare_send_dma(dma_sendbuf, 2);
+
+ i2c_led_begin_dma(drvid);
+}
+
+void i2c_led_send_pwm_dma(uint8_t drvid)
+{
+ //Note: This copies the CURRENT pwm buffer, which may be getting modified
+ memcpy(dma_sendbuf, issidrv[drvid].pwm, ISSI3733_PG1_BYTES);
+ *dma_sendbuf = 0; //Force start location offset to zero
+ i2c_led_prepare_send_dma(dma_sendbuf, ISSI3733_PG1_BYTES);
+
+ i2c_led_begin_dma(drvid);
+}
+
+void i2c_led_send_onoff_dma(uint8_t drvid)
+{
+ //Note: This copies the CURRENT onoff buffer, which may be getting modified
+ memcpy(dma_sendbuf, issidrv[drvid].onoff, ISSI3733_PG0_BYTES);
+ *dma_sendbuf = 0; //Force start location offset to zero
+ i2c_led_prepare_send_dma(dma_sendbuf, ISSI3733_PG0_BYTES);
+
+ i2c_led_begin_dma(drvid);
+}
+
+void i2c_led_q_init(void)
+{
+ memset(i2c_led_q, 0, I2C_Q_SIZE);
+ i2c_led_q_s = 0;
+ i2c_led_q_e = 0;
+ i2c_led_q_running = 0;
+ i2c_led_q_full = 0;
+}
+
+uint8_t i2c_led_q_isempty(void)
+{
+ return i2c_led_q_s == i2c_led_q_e;
+}
+
+uint8_t i2c_led_q_size(void)
+{
+ return (i2c_led_q_e - i2c_led_q_s) % I2C_Q_SIZE;
+}
+
+uint8_t i2c_led_q_available(void)
+{
+ return I2C_Q_SIZE - i2c_led_q_size() - 1; //Never allow end to meet start
+}
+
+void i2c_led_q_add(uint8_t cmd)
+{
+ //WARNING: Always request room before adding commands!
+
+ //Assign command
+ i2c_led_q[i2c_led_q_e] = cmd;
+
+ i2c_led_q_e = (i2c_led_q_e + 1) % I2C_Q_SIZE; //Move end up one or wrap
+}
+
+void i2c_led_q_s_advance(void)
+{
+ i2c_led_q_s = (i2c_led_q_s + 1) % I2C_Q_SIZE; //Move start up one or wrap
+}
+
+//Always request room before adding commands
+//PS: In case the queue somehow gets filled, it will reset if it can not clear up
+//PS: Could only get this to happen through unrealistic timings to overload the I2C bus
+uint8_t i2c_led_q_request_room(uint8_t request_size)
+{
+ if (request_size > i2c_led_q_available())
+ {
+ i2c_led_q_full++;
+
+ if (i2c_led_q_full >= 100) //Give the queue a chance to clear up
+ {
+ led_on;
+ I2C_DMAC_LED_Init();
+ i2c_led_q_init();
+ return 1;
+ }
+
+ return 0;
+ }
+
+ i2c_led_q_full = 0;
+
+ return 1;
+}
+
+uint8_t i2c_led_q_run(void)
+{
+ if (i2c_led_q_isempty())
+ {
+ i2c_led_q_running = 0;
+ return 0;
+ }
+
+ if (i2c_led_q_running) return 1;
+
+ i2c_led_q_running = 1;
+
+#if I2C_LED_USE_DMA != 1
+ while (!i2c_led_q_isempty())
+ {
+#endif
+ //run command
+ if (i2c_led_q[i2c_led_q_s] == I2C_Q_CRWL)
+ {
+ i2c_led_q_s_advance();
+ uint8_t drvid = i2c_led_q[i2c_led_q_s];
+#if I2C_LED_USE_DMA == 1
+ i2c_led_send_CRWL_dma(drvid);
+#else
+ i2c_led_send_CRWL(drvid);
+#endif
+ }
+ else if (i2c_led_q[i2c_led_q_s] == I2C_Q_PAGE_SELECT)
+ {
+ i2c_led_q_s_advance();
+ uint8_t drvid = i2c_led_q[i2c_led_q_s];
+ i2c_led_q_s_advance();
+ uint8_t page = i2c_led_q[i2c_led_q_s];
+#if I2C_LED_USE_DMA == 1
+ i2c_led_select_page_dma(drvid, page);
+#else
+ i2c_led_select_page(drvid, page);
+#endif
+ }
+ else if (i2c_led_q[i2c_led_q_s] == I2C_Q_PWM)
+ {
+ i2c_led_q_s_advance();
+ uint8_t drvid = i2c_led_q[i2c_led_q_s];
+#if I2C_LED_USE_DMA == 1
+ i2c_led_send_pwm_dma(drvid);
+#else
+ i2c_led_send_pwm(drvid);
+#endif
+ }
+ else if (i2c_led_q[i2c_led_q_s] == I2C_Q_GCR)
+ {
+ i2c_led_q_s_advance();
+ uint8_t drvid = i2c_led_q[i2c_led_q_s];
+#if I2C_LED_USE_DMA == 1
+ i2c_led_send_GCR_dma(drvid);
+#else
+ i2c_led_send_GCR(drvid);
+#endif
+ }
+ else if (i2c_led_q[i2c_led_q_s] == I2C_Q_ONOFF)
+ {
+ i2c_led_q_s_advance();
+ uint8_t drvid = i2c_led_q[i2c_led_q_s];
+#if I2C_LED_USE_DMA == 1
+ i2c_led_send_onoff_dma(drvid);
+#else
+ i2c_led_send_onoff(drvid);
+#endif
+ }
+
+ i2c_led_q_s_advance(); //Advance last run command or if the command byte was not serviced
+
+#if I2C_LED_USE_DMA != 1
+ }
+
+ i2c_led_q_running = 0;
+#endif
+
+ return 1;
+}
+#endif //MD_BOOTLOADER
--
cgit v1.2.3