diff --git a/README.org b/README.org index bc42d0e..00889d7 100644 --- a/README.org +++ b/README.org @@ -2,12 +2,18 @@ This project aims to create a generic esp32-s3 based eurorack modular unit—reprogramable to allow for multiple modular possibilities. -* Specs +* Specs - 18 HP - I/O - 4 channel input - 4 channel output - - Output signal 0 -> +5V + - Output signal 0 -> ~+5V - 2 Rotary encoder switches - 4 buttons - 2.2in TFT LCD Display + +* Hardware +** MCP4728 Quad 12bit I2C DAC +- [[https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/22187E.pdf][Datasheet]] +- [[https://learn.adafruit.com/adafruit-mcp4728-i2c-quad-dac][Adafruit Info Page]] +- 0 -> ~+5V out diff --git a/src/main/esp32_eurorack_generic.c b/src/main/esp32_eurorack_generic.c index 7b66f33..e36297c 100644 --- a/src/main/esp32_eurorack_generic.c +++ b/src/main/esp32_eurorack_generic.c @@ -1,6 +1,124 @@ #include +#include +#include "driver/gpio.h" +#include "driver/i2c.h" +#include "esp_err.h" +#include "esp_log.h" +#include "freertos/portmacro.h" +#include "hal/i2c_types.h" + +/* DAC Peripheral Config */ +#define DAC_SCL_PIN 12 +#define DAC_SDA_PIN 13 +#define DAC_LDAC_PIN 14 + +#define DAC_ADDR 0x64 /* I2C Address of DAC */ +#define DAC_VREF 0x00 /* Use Vdd as reference voltage */ +#define DAC_PD 0x00 /* Full power mode */ +#define DAC_GAIN 0x00 /* Since we use external Vref, this doesn't matter */ + +#define ACK_EN 0x1 /* Enable i2c acknowledgment check */ +#define ACK_DIS 0x0 /* Disable i2c acknowledgment check */ +#define ACK_VAL 0x0 /* i2c acknowledgment value */ +#define NACK_VAL 0x1 /* i2c negative-acknowledgment value */ + +static const i2c_port_t I2C_MASTER_PORT = 0; + +static const char *TAG = "EERG"; + + +/* Initialize and configure I2C DAC */ +static void dac_init(void) +{ + ESP_LOGI(TAG, "Initializing DAC I2C connection"); + + /* Configure µC as I2C master */ + i2c_config_t i2c_conf = { + .mode = I2C_MODE_MASTER, + .scl_io_num = DAC_SCL_PIN, + .sda_io_num = DAC_SDA_PIN, + .master.clk_speed = 400000 /* 400kHz for i2c fast mode */ + + }; + i2c_param_config(I2C_MASTER_PORT, &i2c_conf); + + /* Install i2c driver */ + ESP_ERROR_CHECK(i2c_driver_install(I2C_MASTER_PORT, i2c_conf.mode, 0, 0, 0)); + + /* Setup LDAC pin with GPIO. Tied low */ + gpio_reset_pin(DAC_LDAC_PIN); + gpio_set_direction(DAC_LDAC_PIN, GPIO_MODE_OUTPUT); + gpio_set_level(DAC_LDAC_PIN, 0); +} + +/* Tests for acknowledgment of i2c DAC. Return ESP_OK if so */ +static esp_err_t dac_ack_test(void) +{ + ESP_LOGI(TAG, "Testing I2C DAC"); + /* Create i2c command handle */ + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (DAC_ADDR << 1) | I2C_MASTER_READ, ACK_EN); /* R/W byte is LSB of DAC address */ + i2c_master_stop(cmd); + esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_PORT, cmd, 1000 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + + return ret; +} + +/* Brings all DAC output channels from 0 -> ~+5V */ +static esp_err_t dac_out_test(void) +{ + esp_err_t ret; + uint16_t test_value = 0; /* The value sent to DAC input registers */ + i2c_cmd_handle_t cmd; + + for (uint16_t i = 0; i < 4096; i++){ + + test_value = i; + + cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (DAC_ADDR << 1) | I2C_MASTER_WRITE, ACK_EN); /* R/W byte is LSB of DAC address */ + i2c_master_write_byte(cmd, 0x50, ACK_EN); /* Multi-write to all channels */ + + /* For each channel [A-D] write 2 bytes to input register */ + /* V_ref + PD1 + PD0 + Gx + D11-D8 | D7-D0 */ + for (uint8_t i = 0; i < 4; i++) { + uint8_t bytes[2]; + bytes[0] = ((uint8_t) DAC_VREF << 7) | ((uint8_t) DAC_PD << 5) | ((uint8_t) DAC_GAIN << 4) | (test_value >> 8); + bytes[1] = test_value; + i2c_master_write_byte(cmd, bytes[0], ACK_EN); + i2c_master_write_byte(cmd, bytes[1], ACK_EN); + } + + i2c_master_stop(cmd); + + /* Issue the multi-write command */ + /* TODO need to create array of returns and check them for error */ + ret = i2c_master_cmd_begin(I2C_MASTER_PORT, cmd, 1000 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + } + return ret; +} + +/* Main application entrance */ void app_main(void) { + /* Initialize and configure I2C DAC */ + dac_init(); + /* Test DAC */ + esp_err_t ret = dac_ack_test(); + if (ret != ESP_OK){ + ESP_LOGE(TAG, "Failed to initialize DAC"); + } else { + ESP_LOGI(TAG, "Sucessfully initialized DAC"); + } + + /* Loop to test DAC output */ + while (1) { + dac_out_test(); + } }