From c9f3a47c5794742d7d91949089e92abc1467de20 Mon Sep 17 00:00:00 2001 From: CamDavidsonPilon Date: Fri, 16 Aug 2024 14:05:35 -0400 Subject: [PATCH 1/6] try this new version --- .github/workflows/cmake.yml | 2 +- main.c | 70 +++++++++++++++++++++++++------------ 2 files changed, 48 insertions(+), 24 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 8811012..d0a64de 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -67,7 +67,7 @@ jobs: cmake --build . --config $BUILD_TYPE -j 2 - name: Upload build result - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: elf_file path: ${{runner.workspace}}/build/main.elf diff --git a/main.c b/main.c index 12779bd..f61a449 100644 --- a/main.c +++ b/main.c @@ -9,32 +9,32 @@ /* The code implements the following i2c API 1. Write to any of the first 4 addresses (0, 1, 2, 3) to set the 8-bit duty cycle of the corresponding PWM 2. Read from any of the next 4 addresses (4, 5, 6, 7) to get the 16 bit ADC value of the corresponding ADC -2. Read from address 8 to return the version of this code. +3. Read from address 8 to return the version of this code. Here are some examples of using i2cset and i2cget to interact with this program: -To set the duty cycle of the PWM channel corresponding to address 0 to 75%, you could use the following i2cset command: +To set the duty cycle of the PWM channel corresponding to LED channel A to 75%, you could use the following i2cset command: > i2cset -y 1 0x30 0 0xC0 To read the 16-bit ADC value of the ADC channel corresponding to address 4, you could use the following i2cget command: -> i2cget -y 1 0x30 w 4 +> i2cget -y 1 0x30 4 w + +To get the version information: + +> i2cget -y 1 0x30 8 w -Note that the -y flag is used to automatically answer yes to any prompt from i2cset or i2cget. -The 1 after the -y flag specifies the i2c bus number to use, and the 0x30 specifies the i2c address of the peripheral. -The 0 and w in the i2cset and i2cget commands, respectively, specify the starting register address to be accessed. -The 4 in the i2cget command specifies the address of the ADC channel to read. */ // define I2C addresses to be used for this peripheral #define I2C1_PERIPHERAL_ADDR 0x30 -// GPIO pins to use for I2C +// Pico GPIO pins to use for I2C #define GPIO_SDA0 14 #define GPIO_SCK0 15 -// GPIO pins to use for PWM -> LED channels +// Pico GPIO pins to use for PWM -> LED channels #define LED_CHANNEL_A_PIN 16 #define LED_CHANNEL_B_PIN 17 #define LED_CHANNEL_C_PIN 18 @@ -42,20 +42,20 @@ The 4 in the i2cget command specifies the address of the ADC channel to read. // define firmware version that can be read over i2c #define VERSION_MAJOR 0 -#define VERSION_MINOR 2 +#define VERSION_MINOR 3 // first 4 addresses are for the PWM channels for LEDS (A, B, C, D) // second 4 addresses are for the ADCs (0, 1, 2, 3) uint8_t pointer = 0; -// store the GPIO pins of the PWMs +// store the Pico GPIO pins of the PWMs uint8_t pwm_channels[4] = {LED_CHANNEL_A_PIN, LED_CHANNEL_B_PIN, LED_CHANNEL_C_PIN, LED_CHANNEL_D_PIN}; // store the duty cycles of the PWMs uint8_t pwm_duty_cycles[4]; -void set_up_pwm_pin(uint pin) { +void set_up_pwm_pin(uint pin) { // starts at duty_cycle = 0, hz = 325k gpio_set_function(pin, GPIO_FUNC_PWM); uint slice_num = pwm_gpio_to_slice_num(pin); @@ -69,9 +69,20 @@ void set_up_pwm_pin(uint pin) { void i2c1_irq_handler() { + // Get interrupt status uint32_t status = i2c1->hw->intr_stat; + // Check for NACK signals from the master + if (status & I2C_IC_INTR_STAT_R_RX_DONE_BITS || status & I2C_IC_INTR_STAT_R_TX_ABRT_BITS) { + // Handle NACK signal (e.g., log the error, reset a state variable, etc.) + // ... + + // Clear the NACK interrupt + i2c1->hw->clr_rx_done; + i2c1->hw->clr_tx_abrt; + } + // Check to see if we have received data from the I2C controller if (status & I2C_IC_INTR_STAT_R_RX_FULL_BITS) { @@ -83,18 +94,22 @@ void i2c1_irq_handler() { // If so treat it as the address to use pointer = (uint8_t)(value & I2C_IC_DATA_CMD_DAT_BITS); + // Validate the received I2C address + if (pointer > 8) { + // If the address is not within the valid range + pointer = 0xFF; + } } else { if (pointer <= 3){ // If not 1st byte then store the data in the RAM - // and increment the address to point to next byte pwm_duty_cycles[pointer] = (uint8_t)(value & I2C_IC_DATA_CMD_DAT_BITS); pwm_set_gpio_level(pwm_channels[pointer], (uint8_t) pwm_duty_cycles[pointer]); } } } - // Check to see if the I2C controller is requesting data from the RAM + // Check to see if the I2C controller is requesting data if (status & I2C_IC_INTR_STAT_R_RD_REQ_BITS) { if (pointer >= 4 && pointer <= 7){ uint8_t adc_input = pointer - 4; @@ -102,20 +117,29 @@ void i2c1_irq_handler() { // since the adc_read will return maximum 2**12, and I can // send up to 2**16 data over two bytes in i2c, I can theoretically - // read up to 2**4 = 16 times here. - uint16_t raw = 0; - int i; - for (i = 0; i < 16; ++i){ - raw = raw + adc_read(); + // read up to 2**4 = 16 times here, since 2**12 * 16 = two bytes + + // we can treat this as a single sample from an 16bit ADC, and I can sample multiple times, and take the average. + + const int n_samples = 16; + const int samples_to_fill_2bytes = 16; + uint32_t running_sum = 0; + for (int j = 0; j < n_samples; ++j){ + for (int i = 0; i < samples_to_fill_2bytes; ++i){ + running_sum = running_sum + adc_read(); + sleep_us(5); + } } - i2c1->hw->data_cmd = (raw & 0xFF); // Send the low-order byte - i2c1->hw->data_cmd = (raw >> 8); // Send the high-order byte + uint16_t average = (uint16_t)(running_sum / n_samples); + + i2c1->hw->data_cmd = (average & 0xFF); // Send the low-order byte + i2c1->hw->data_cmd = (average >> 8); // Send the high-order byte } else if (pointer == 8) { i2c1->hw->data_cmd = VERSION_MINOR; i2c1->hw->data_cmd = VERSION_MAJOR; } else { - i2c1->hw->data_cmd = 0; // return 0 - i2c1->hw->data_cmd = 0; + i2c1->hw->data_cmd = 0xFF; // return 0xFF as an error code + i2c1->hw->data_cmd = 0xFF; } // Clear the interrupt From db8264ccca1fde0b9d7f9d984c7efcbdd0e8dc86 Mon Sep 17 00:00:00 2001 From: CamDavidsonPilon Date: Mon, 19 Aug 2024 09:32:27 -0400 Subject: [PATCH 2/6] try this --- .github/workflows/cmake.yml | 10 ++-- main.c | 94 +++++++------------------------------ 2 files changed, 21 insertions(+), 83 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index d0a64de..b5c0e74 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -26,13 +26,13 @@ jobs: PICO_SDK_PATH: $GITHUB_WORKSPACE/pico-sdk steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true # Check out the Pico SDK - name: Checkout Pico SDK - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: raspberrypi/pico-sdk path: pico-sdk @@ -40,7 +40,7 @@ jobs: # Check out the Pico Extras - name: Checkout Pico Extras - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: raspberrypi/pico-extras path: pico-extras @@ -67,9 +67,9 @@ jobs: cmake --build . --config $BUILD_TYPE -j 2 - name: Upload build result - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v3 with: - name: elf_file + name: main.elf.zip path: ${{runner.workspace}}/build/main.elf - name: Upload elf to GH release page diff --git a/main.c b/main.c index f61a449..cab0f9d 100644 --- a/main.c +++ b/main.c @@ -6,57 +6,27 @@ #include "hardware/clocks.h" -/* The code implements the following i2c API -1. Write to any of the first 4 addresses (0, 1, 2, 3) to set the 8-bit duty cycle of the corresponding PWM -2. Read from any of the next 4 addresses (4, 5, 6, 7) to get the 16 bit ADC value of the corresponding ADC -3. Read from address 8 to return the version of this code. - -Here are some examples of using i2cset and i2cget to interact with this program: - -To set the duty cycle of the PWM channel corresponding to LED channel A to 75%, you could use the following i2cset command: - -> i2cset -y 1 0x30 0 0xC0 - -To read the 16-bit ADC value of the ADC channel corresponding to address 4, you could use the following i2cget command: - -> i2cget -y 1 0x30 4 w - -To get the version information: - -> i2cget -y 1 0x30 8 w - -*/ - -// define I2C addresses to be used for this peripheral #define I2C1_PERIPHERAL_ADDR 0x30 -// Pico GPIO pins to use for I2C #define GPIO_SDA0 14 #define GPIO_SCK0 15 -// Pico GPIO pins to use for PWM -> LED channels #define LED_CHANNEL_A_PIN 16 #define LED_CHANNEL_B_PIN 17 #define LED_CHANNEL_C_PIN 18 #define LED_CHANNEL_D_PIN 19 -// define firmware version that can be read over i2c #define VERSION_MAJOR 0 #define VERSION_MINOR 3 -// first 4 addresses are for the PWM channels for LEDS (A, B, C, D) -// second 4 addresses are for the ADCs (0, 1, 2, 3) uint8_t pointer = 0; - -// store the Pico GPIO pins of the PWMs uint8_t pwm_channels[4] = {LED_CHANNEL_A_PIN, LED_CHANNEL_B_PIN, LED_CHANNEL_C_PIN, LED_CHANNEL_D_PIN}; - -// store the duty cycles of the PWMs uint8_t pwm_duty_cycles[4]; +const int randomArray[16] = {2, -1, 1, 0, -2, 2, -1, 0, 1, -2, 0, 2, -1, 1, 0, -2}; + void set_up_pwm_pin(uint pin) { - // starts at duty_cycle = 0, hz = 325k gpio_set_function(pin, GPIO_FUNC_PWM); uint slice_num = pwm_gpio_to_slice_num(pin); pwm_config config = pwm_get_default_config(); @@ -67,67 +37,49 @@ void set_up_pwm_pin(uint pin) { pwm_set_gpio_level(pin, 0); }; -void i2c1_irq_handler() { - +void reset_i2c_bus() { + i2c_deinit(i2c1); + i2c_init(i2c1, 100000); + i2c_set_slave_mode(i2c1, true, I2C1_PERIPHERAL_ADDR); +} - // Get interrupt status +void i2c1_irq_handler() { uint32_t status = i2c1->hw->intr_stat; - // Check for NACK signals from the master if (status & I2C_IC_INTR_STAT_R_RX_DONE_BITS || status & I2C_IC_INTR_STAT_R_TX_ABRT_BITS) { - // Handle NACK signal (e.g., log the error, reset a state variable, etc.) - // ... - - // Clear the NACK interrupt + pointer = 0xFF; // Reset pointer on NACK or TX abort i2c1->hw->clr_rx_done; i2c1->hw->clr_tx_abrt; } - // Check to see if we have received data from the I2C controller if (status & I2C_IC_INTR_STAT_R_RX_FULL_BITS) { - - // Read the data (this will clear the interrupt) uint32_t value = i2c1->hw->data_cmd; - // Check if this is the 1st byte we have received if (value & I2C_IC_DATA_CMD_FIRST_DATA_BYTE_BITS) { - - // If so treat it as the address to use pointer = (uint8_t)(value & I2C_IC_DATA_CMD_DAT_BITS); - // Validate the received I2C address if (pointer > 8) { - // If the address is not within the valid range - pointer = 0xFF; + pointer = 0xFF; // Ignore unexpected addresses } - } else { if (pointer <= 3){ - // If not 1st byte then store the data in the RAM pwm_duty_cycles[pointer] = (uint8_t)(value & I2C_IC_DATA_CMD_DAT_BITS); - pwm_set_gpio_level(pwm_channels[pointer], (uint8_t) pwm_duty_cycles[pointer]); + pwm_set_gpio_level(pwm_channels[pointer], pwm_duty_cycles[pointer]); } } } - // Check to see if the I2C controller is requesting data if (status & I2C_IC_INTR_STAT_R_RD_REQ_BITS) { if (pointer >= 4 && pointer <= 7){ uint8_t adc_input = pointer - 4; adc_select_input(adc_input); - // since the adc_read will return maximum 2**12, and I can - // send up to 2**16 data over two bytes in i2c, I can theoretically - // read up to 2**4 = 16 times here, since 2**12 * 16 = two bytes - - // we can treat this as a single sample from an 16bit ADC, and I can sample multiple times, and take the average. - const int n_samples = 16; const int samples_to_fill_2bytes = 16; uint32_t running_sum = 0; for (int j = 0; j < n_samples; ++j){ for (int i = 0; i < samples_to_fill_2bytes; ++i){ running_sum = running_sum + adc_read(); - sleep_us(5); + sleep_us(5 + randomArray[j]); } } uint16_t average = (uint16_t)(running_sum / n_samples); @@ -142,55 +94,41 @@ void i2c1_irq_handler() { i2c1->hw->data_cmd = 0xFF; } - // Clear the interrupt i2c1->hw->clr_rd_req; } -} + i2c1->hw->clr_intr; // Clear all interrupts +} -// Main loop - initializes system and then loops while interrupts get on with processing the data int main() { + stdio_init_all(); - // setup ADC - stdio_init_all(); - - // Initialise ADCs adc_init(); - // Make sure GPIO is high-impedance, no pull-ups etc adc_gpio_init(26); adc_gpio_init(27); adc_gpio_init(28); adc_gpio_init(29); - // Select ADC input 0 initially (GPIO26) adc_select_input(0); - // Setup I2C1 as peripheral - i2c_init(i2c1, 100000); + i2c_init(i2c1, 100000); i2c_set_slave_mode(i2c1, true, I2C1_PERIPHERAL_ADDR); - // Setup GPIO pins to use and add pull up resistors gpio_set_function(GPIO_SDA0, GPIO_FUNC_I2C); gpio_set_function(GPIO_SCK0, GPIO_FUNC_I2C); gpio_pull_up(GPIO_SDA0); gpio_pull_up(GPIO_SCK0); - // set up PWMs set_up_pwm_pin(LED_CHANNEL_A_PIN); set_up_pwm_pin(LED_CHANNEL_B_PIN); set_up_pwm_pin(LED_CHANNEL_C_PIN); set_up_pwm_pin(LED_CHANNEL_D_PIN); - // Enable the I2C interrupts we want to process i2c1->hw->intr_mask = (I2C_IC_INTR_MASK_M_RD_REQ_BITS | I2C_IC_INTR_MASK_M_RX_FULL_BITS); - // Set up the interrupt handler to service I2C interrupts irq_set_exclusive_handler(I2C1_IRQ, i2c1_irq_handler); - - // Enable I2C interrupt irq_set_enabled(I2C1_IRQ, true); - // Do nothing in main loop while (true) { tight_loop_contents(); } From 38c8d7d4982fba135572a2a3258b29cb1249a8a9 Mon Sep 17 00:00:00 2001 From: CamDavidsonPilon Date: Mon, 19 Aug 2024 10:43:21 -0400 Subject: [PATCH 3/6] try this --- .github/workflows/cmake.yml | 4 ++-- main.c | 47 ++++++++++++++++++------------------- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index b5c0e74..745ca89 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -67,9 +67,9 @@ jobs: cmake --build . --config $BUILD_TYPE -j 2 - name: Upload build result - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: main.elf.zip + name: main.elf path: ${{runner.workspace}}/build/main.elf - name: Upload elf to GH release page diff --git a/main.c b/main.c index cab0f9d..18ba5d8 100644 --- a/main.c +++ b/main.c @@ -37,69 +37,68 @@ void set_up_pwm_pin(uint pin) { pwm_set_gpio_level(pin, 0); }; -void reset_i2c_bus() { - i2c_deinit(i2c1); - i2c_init(i2c1, 100000); - i2c_set_slave_mode(i2c1, true, I2C1_PERIPHERAL_ADDR); -} void i2c1_irq_handler() { + // Get interrupt status uint32_t status = i2c1->hw->intr_stat; - if (status & I2C_IC_INTR_STAT_R_RX_DONE_BITS || status & I2C_IC_INTR_STAT_R_TX_ABRT_BITS) { - pointer = 0xFF; // Reset pointer on NACK or TX abort - i2c1->hw->clr_rx_done; + // Check for NACK signals from the master or TX abort + if (status & I2C_IC_INTR_STAT_R_TX_ABRT_BITS) { + // Clear the TX abort interrupt i2c1->hw->clr_tx_abrt; } + // Check to see if we have received data from the I2C controller if (status & I2C_IC_INTR_STAT_R_RX_FULL_BITS) { uint32_t value = i2c1->hw->data_cmd; - if (value & I2C_IC_DATA_CMD_FIRST_DATA_BYTE_BITS) { pointer = (uint8_t)(value & I2C_IC_DATA_CMD_DAT_BITS); if (pointer > 8) { - pointer = 0xFF; // Ignore unexpected addresses + pointer = 0xFF; // invalid address } } else { - if (pointer <= 3){ + if (pointer <= 3) { pwm_duty_cycles[pointer] = (uint8_t)(value & I2C_IC_DATA_CMD_DAT_BITS); - pwm_set_gpio_level(pwm_channels[pointer], pwm_duty_cycles[pointer]); + pwm_set_gpio_level(pwm_channels[pointer], (uint8_t) pwm_duty_cycles[pointer]); } } } + // Check to see if the I2C controller is requesting data if (status & I2C_IC_INTR_STAT_R_RD_REQ_BITS) { - if (pointer >= 4 && pointer <= 7){ + if (pointer >= 4 && pointer <= 7) { uint8_t adc_input = pointer - 4; adc_select_input(adc_input); - const int n_samples = 16; - const int samples_to_fill_2bytes = 16; uint32_t running_sum = 0; - for (int j = 0; j < n_samples; ++j){ - for (int i = 0; i < samples_to_fill_2bytes; ++i){ - running_sum = running_sum + adc_read(); + for (int j = 0; j < 16; ++j) { + for (int i = 0; i < 16; ++i) { + running_sum += adc_read(); sleep_us(5 + randomArray[j]); } } - uint16_t average = (uint16_t)(running_sum / n_samples); - - i2c1->hw->data_cmd = (average & 0xFF); // Send the low-order byte - i2c1->hw->data_cmd = (average >> 8); // Send the high-order byte + uint16_t average = (uint16_t)(running_sum / 16); + i2c1->hw->data_cmd = (average & 0xFF); + i2c1->hw->data_cmd = (average >> 8); } else if (pointer == 8) { i2c1->hw->data_cmd = VERSION_MINOR; i2c1->hw->data_cmd = VERSION_MAJOR; } else { - i2c1->hw->data_cmd = 0xFF; // return 0xFF as an error code + i2c1->hw->data_cmd = 0xFF; i2c1->hw->data_cmd = 0xFF; } + // Clear the read request interrupt i2c1->hw->clr_rd_req; } - i2c1->hw->clr_intr; // Clear all interrupts + // Clear any other interrupts that might have been set + if (status & I2C_IC_INTR_STAT_R_RX_DONE_BITS) { + i2c1->hw->clr_rx_done; + } } + int main() { stdio_init_all(); From e2d2ffc7528e0cadc6daaa5be6d9cd95f840c47a Mon Sep 17 00:00:00 2001 From: CamDavidsonPilon Date: Mon, 19 Aug 2024 10:53:13 -0400 Subject: [PATCH 4/6] what if we used 29, which should be a quick read --- main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.c b/main.c index 18ba5d8..8dde282 100644 --- a/main.c +++ b/main.c @@ -6,7 +6,7 @@ #include "hardware/clocks.h" -#define I2C1_PERIPHERAL_ADDR 0x30 +#define I2C1_PERIPHERAL_ADDR 0x29 #define GPIO_SDA0 14 #define GPIO_SCK0 15 From 261706e757902cff5d9c4c1c080030649919272f Mon Sep 17 00:00:00 2001 From: CamDavidsonPilon Date: Mon, 19 Aug 2024 11:07:20 -0400 Subject: [PATCH 5/6] 0x2C --- README.md | 6 +++--- main.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 76aefc2..b5afc7a 100644 --- a/README.md +++ b/README.md @@ -28,13 +28,13 @@ Here are some examples of using i2cset and i2cget to interact with this program: To set the duty cycle of the PWM channel corresponding to address 0 to 75%, you could use the following i2cset command: - i2cset -y 1 0x30 0 0xC0 + i2cset -y 1 0x2C 0 0xC0 To read the 16-bit ADC value of the ADC channel corresponding to address 4, you could use the following i2cget command: - i2cget -y 1 0x30 w 4 + i2cget -y 1 0x2C w 4 Note that the -y flag is used to automatically answer yes to any prompt from i2cset or i2cget. -The 1 after the -y flag specifies the i2c bus number to use, and the 0x30 specifies the i2c address of the peripheral. +The 1 after the -y flag specifies the i2c bus number to use, and the 0x2C specifies the i2c address of the peripheral. The 0 and w in the i2cset and i2cget commands, respectively, specify the starting register address to be accessed. The 4 in the i2cget command specifies the address of the ADC channel to read. diff --git a/main.c b/main.c index 8dde282..288d16d 100644 --- a/main.c +++ b/main.c @@ -6,7 +6,7 @@ #include "hardware/clocks.h" -#define I2C1_PERIPHERAL_ADDR 0x29 +#define I2C1_PERIPHERAL_ADDR 0x2C #define GPIO_SDA0 14 #define GPIO_SCK0 15 From 783c8dfab2fc0fe2916aa72b7d8f472a895a8a22 Mon Sep 17 00:00:00 2001 From: CamDavidsonPilon Date: Mon, 19 Aug 2024 11:17:09 -0400 Subject: [PATCH 6/6] add back comments --- main.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/main.c b/main.c index 288d16d..489bc81 100644 --- a/main.c +++ b/main.c @@ -5,12 +5,30 @@ #include "hardware/pwm.h" #include "hardware/clocks.h" +/* The code implements the following i2c API +1. Write to any of the first 4 addresses (0, 1, 2, 3) to set the 8-bit duty cycle of the corresponding PWM +2. Read from any of the next 4 addresses (4, 5, 6, 7) to get the 16 bit ADC value of the corresponding ADC +2. Read from address 8 to return the version of this code. + +Here are some examples of using i2cset and i2cget to interact with this program: +To set the duty cycle of the PWM channel corresponding to address 0 to 75%, you could use the following i2cset command: +> i2cset -y 1 0x30 0 0xC0 +To read the 16-bit ADC value of the ADC channel corresponding to address 4, you could use the following i2cget command: +> i2cget -y 1 0x30 w 4 +Note that the -y flag is used to automatically answer yes to any prompt from i2cset or i2cget. +The 1 after the -y flag specifies the i2c bus number to use, and the 0x30 specifies the i2c address of the peripheral. +The 0 and w in the i2cset and i2cget commands, respectively, specify the starting register address to be accessed. +The 4 in the i2cget command specifies the address of the ADC channel to read. +*/ + +// define I2C addresses to be used for this peripheral #define I2C1_PERIPHERAL_ADDR 0x2C #define GPIO_SDA0 14 #define GPIO_SCK0 15 +// GPIO pins to use for PWM -> LED channels #define LED_CHANNEL_A_PIN 16 #define LED_CHANNEL_B_PIN 17 #define LED_CHANNEL_C_PIN 18 @@ -19,8 +37,12 @@ #define VERSION_MAJOR 0 #define VERSION_MINOR 3 +// first 4 addresses are for the PWM channels for LEDS (A, B, C, D) +// second 4 addresses are for the ADCs (0, 1, 2, 3) uint8_t pointer = 0; +// store the GPIO pins of the PWMs uint8_t pwm_channels[4] = {LED_CHANNEL_A_PIN, LED_CHANNEL_B_PIN, LED_CHANNEL_C_PIN, LED_CHANNEL_D_PIN}; +// store the duty cycles of the PWMs uint8_t pwm_duty_cycles[4]; const int randomArray[16] = {2, -1, 1, 0, -2, 2, -1, 0, 1, -2, 0, 2, -1, 1, 0, -2}; @@ -70,6 +92,9 @@ void i2c1_irq_handler() { uint8_t adc_input = pointer - 4; adc_select_input(adc_input); + // since the adc_read will return maximum 2**12, and I can + // send up to 2**16 data over two bytes in i2c, I can theoretically + // read up to 2**4 = 16 times here. uint32_t running_sum = 0; for (int j = 0; j < 16; ++j) { for (int i = 0; i < 16; ++i) { @@ -108,6 +133,7 @@ int main() { adc_gpio_init(28); adc_gpio_init(29); + // Select ADC input 0 initially (GPIO26) adc_select_input(0); i2c_init(i2c1, 100000); @@ -123,9 +149,11 @@ int main() { set_up_pwm_pin(LED_CHANNEL_C_PIN); set_up_pwm_pin(LED_CHANNEL_D_PIN); + // Enable the I2C interrupts we want to process i2c1->hw->intr_mask = (I2C_IC_INTR_MASK_M_RD_REQ_BITS | I2C_IC_INTR_MASK_M_RX_FULL_BITS); - + // Set up the interrupt handler to service I2C interrupts irq_set_exclusive_handler(I2C1_IRQ, i2c1_irq_handler); + // Enable I2C interrupt irq_set_enabled(I2C1_IRQ, true); while (true) {