summaryrefslogtreecommitdiff
path: root/tmk_core/protocol/arm_atsam/i2c_master.c
diff options
context:
space:
mode:
Diffstat (limited to 'tmk_core/protocol/arm_atsam/i2c_master.c')
-rw-r--r--tmk_core/protocol/arm_atsam/i2c_master.c132
1 files changed, 68 insertions, 64 deletions
diff --git a/tmk_core/protocol/arm_atsam/i2c_master.c b/tmk_core/protocol/arm_atsam/i2c_master.c
index af046625f4..6b0b9a703b 100644
--- a/tmk_core/protocol/arm_atsam/i2c_master.c
+++ b/tmk_core/protocol/arm_atsam/i2c_master.c
@@ -26,21 +26,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
# 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
+# define I2C_LED_USE_DMA 1 // Set 1 to use background DMA transfers for leds, Set 0 to use inline software transfers
DmacDescriptor dmac_desc;
DmacDescriptor dmac_desc_wb;
-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 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
+static uint8_t dma_sendbuf[I2C_DMA_MAX_SEND]; // Data being written to I2C
volatile uint8_t i2c_led_q_running;
-#endif // !defined(MD_BOOTLOADER) && defined(RGB_MATRIX_ENABLE)
+#endif // !defined(MD_BOOTLOADER) && defined(RGB_MATRIX_ENABLE)
void i2c0_init(void) {
DBGC(DC_I2C0_INIT_BEGIN);
@@ -56,23 +56,23 @@ void i2c0_init(void) {
// 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.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.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
+ 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
+ } // Wait for SYNCBUSY.ENABLE to clear
- SERCOM0->I2CM.STATUS.bit.BUSSTATE = 1; // Force into IDLE state
+ 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
+ } // Wait while not idle
DBGC(DC_I2C0_INIT_COMPLETE);
}
@@ -139,27 +139,27 @@ void i2c1_init(void) {
/* 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.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)
+ 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)
+ 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
+ } // Wait for SYNCBUSY.ENABLE to clear
- SERCOM1->I2CM.STATUS.bit.BUSSTATE = 1; // BUSSTATE: Force into IDLE state (sync SYNCBUSY.SYSOP)
+ 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
+ } // Wait while not idle
DBGC(DC_I2C1_INIT_COMPLETE);
}
@@ -240,7 +240,7 @@ void i2c_led_send_onoff(uint8_t drvid) {
}
# endif
- *issidrv[drvid].onoff = 0; // Force start location offset to zero
+ *issidrv[drvid].onoff = 0; // Force start location offset to zero
i2c1_transmit(issidrv[drvid].addr, issidrv[drvid].onoff, ISSI3733_PG0_BYTES, 0);
}
@@ -265,7 +265,7 @@ void i2c_led_send_pwm(uint8_t drvid) {
}
# endif
- *issidrv[drvid].pwm = 0; // Force start location offset to zero
+ *issidrv[drvid].pwm = 0; // Force start location offset to zero
i2c1_transmit(issidrv[drvid].addr, issidrv[drvid].pwm, ISSI3733_PG1_BYTES, 0);
}
@@ -300,12 +300,12 @@ uint8_t I2C3733_Init_Drivers(void) {
// Set up master device
i2c_led_send_CRWL(0);
i2c_led_select_page(0, 3);
- i2c_led_send_mode_op_gcr(0, 0, ISSI3733_CR_SSD_NORMAL); // No SYNC due to brightness mismatch with second driver
+ i2c_led_send_mode_op_gcr(0, 0, ISSI3733_CR_SSD_NORMAL); // No SYNC due to brightness mismatch with second driver
// Set up slave device
i2c_led_send_CRWL(1);
i2c_led_select_page(1, 3);
- i2c_led_send_mode_op_gcr(1, 0, ISSI3733_CR_SSD_NORMAL); // No SYNC due to brightness mismatch with first driver and slight flicker at rgb values 1,2
+ i2c_led_send_mode_op_gcr(1, 0, ISSI3733_CR_SSD_NORMAL); // No SYNC due to brightness mismatch with first driver and slight flicker at rgb values 1,2
i2c_led_send_CRWL(0);
i2c_led_select_page(0, 3);
@@ -326,41 +326,41 @@ void I2C_DMAC_LED_Init(void) {
DBGC(DC_I2C_DMAC_LED_INIT_BEGIN);
// Disable device
- dmac->CTRL.bit.DMAENABLE = 0; // Disable DMAC
+ 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
+ } // 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
+ } // 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)
+ 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
+ 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
+ } // 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
+ } // 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
+ 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
+ dmac->CTRL.bit.DMAENABLE = 1; // Enable DMAC
while (dmac->CTRL.bit.DMAENABLE == 0) {
- } // Wait for enable state
+ } // Wait for enable state
DBGC(DC_I2C_DMAC_LED_INIT_COMPLETE);
}
@@ -377,14 +377,14 @@ void I2C3733_Control_Set(uint8_t state) {
}
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
+ 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) {
@@ -397,9 +397,9 @@ void i2c_led_prepare_send_dma(uint8_t *data, uint8_t len) {
}
void i2c_led_begin_dma(uint8_t drvid) {
- DMAC->Channel[0].CHCTRLA.bit.ENABLE = 1; // Enable the channel
+ 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
+ SERCOM1->I2CM.ADDR.reg = (dmac_desc.BTCNT.reg << 16) | 0x2000 | issidrv[drvid].addr; // Begin transfer
}
void i2c_led_send_CRWL_dma(uint8_t drvid) {
@@ -429,7 +429,7 @@ void i2c_led_send_GCR_dma(uint8_t 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
+ *dma_sendbuf = 0; // Force start location offset to zero
i2c_led_prepare_send_dma(dma_sendbuf, ISSI3733_PG1_BYTES);
i2c_led_begin_dma(drvid);
@@ -438,7 +438,7 @@ void i2c_led_send_pwm_dma(uint8_t 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
+ *dma_sendbuf = 0; // Force start location offset to zero
i2c_led_prepare_send_dma(dma_sendbuf, ISSI3733_PG0_BYTES);
i2c_led_begin_dma(drvid);
@@ -452,12 +452,16 @@ void i2c_led_q_init(void) {
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_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_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
+ return I2C_Q_SIZE - i2c_led_q_size() - 1; // Never allow end to meet start
}
void i2c_led_q_add(uint8_t cmd) {
@@ -466,11 +470,11 @@ void i2c_led_q_add(uint8_t cmd) {
// 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
+ 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
+ i2c_led_q_s = (i2c_led_q_s + 1) % I2C_Q_SIZE; // Move start up one or wrap
}
// Always request room before adding commands
@@ -480,7 +484,7 @@ 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
+ if (i2c_led_q_full >= 100) // Give the queue a chance to clear up
{
DBG_LED_ON;
I2C_DMAC_LED_Init();
@@ -554,7 +558,7 @@ uint8_t i2c_led_q_run(void) {
# endif
}
- i2c_led_q_s_advance(); // Advance last run command or if the command byte was not serviced
+ i2c_led_q_s_advance(); // Advance last run command or if the command byte was not serviced
# if I2C_LED_USE_DMA != 1
}
@@ -583,4 +587,4 @@ i2c_status_t i2c_transmit(uint8_t address, const uint8_t *data, uint16_t length,
return ret ? I2C_STATUS_SUCCESS : I2C_STATUS_ERROR;
}
-#endif // !defined(MD_BOOTLOADER) && defined(RGB_MATRIX_ENABLE)
+#endif // !defined(MD_BOOTLOADER) && defined(RGB_MATRIX_ENABLE)