diff --git a/main/epd7in5.c b/main/epd7in5.c index 0fd3049..f53b195 100644 --- a/main/epd7in5.c +++ b/main/epd7in5.c @@ -109,6 +109,46 @@ esp_err_t epd7in5_v3_init(epd7in5_v3_t *epd) return ESP_OK; } +esp_err_t epd7in5_v3_init_fast(epd7in5_v3_t *epd) +{ + spi_device_interface_config_t devcfg = { + .clock_speed_hz = 20 * 1000 * 1000, // 2 MHz + .mode = 0, // SPI mode 0 + .spics_io_num = epd->pin_cs, + .queue_size = 1, + .flags = SPI_DEVICE_HALFDUPLEX // use .flags |= SPI_DEVICE_3WIRE if necessary + }; + ESP_RETURN_ON_ERROR(spi_bus_add_device(epd->spi_host, &devcfg, &epd->spi), "add device", ret); + + gpio_set_level(epd->pin_rst, 1); + vTaskDelay(pdMS_TO_TICKS(20)); + gpio_set_level(epd->pin_rst, 0); + vTaskDelay(pdMS_TO_TICKS(4)); + gpio_set_level(epd->pin_rst, 1); + vTaskDelay(pdMS_TO_TICKS(20)); + + epd7in5_v3_send_command(epd, 0x50); + epd7in5_v3_send_data(epd, 0x10); + epd7in5_v3_send_data(epd, 0x07); + + epd7in5_v3_send_command(epd, 0x04); + vTaskDelay(pdMS_TO_TICKS(100)); + epd7in5_v3_busy_wait(epd); + + epd7in5_v3_send_command(epd, 0x06); + epd7in5_v3_send_data(epd, 0x27); + epd7in5_v3_send_data(epd, 0x27); + epd7in5_v3_send_data(epd, 0x18); + epd7in5_v3_send_data(epd, 0x17); + + epd7in5_v3_send_command(epd, 0xE0); + epd7in5_v3_send_data(epd, 0x02); + epd7in5_v3_send_command(epd, 0xE5); + epd7in5_v3_send_data(epd, 0x5A); + + return ESP_OK; +} + esp_err_t epd7in5_v3_send_command(epd7in5_v3_t *epd, uint8_t cmd) { esp_err_t ret; diff --git a/main/epd7in5.h b/main/epd7in5.h index c176d2b..534b55c 100644 --- a/main/epd7in5.h +++ b/main/epd7in5.h @@ -78,6 +78,13 @@ esp_err_t epd7in5_v3_create(epd7in5_v3_t *epd, spi_host_device_t host); */ esp_err_t epd7in5_v3_init(epd7in5_v3_t *epd); +/** + * @brief Initialize the EPD panel with fast settings (no full refresh). + * @param epd Pointer to an epd7in5_v3_t struct (must be allocated by caller). + * @return ESP_OK on success, or an error code. + */ +esp_err_t epd7in5_v3_init_fast(epd7in5_v3_t *epd); + /** * @brief Send a blocking command byte. */ diff --git a/main/main.c b/main/main.c index 0afd57e..2ced578 100755 --- a/main/main.c +++ b/main/main.c @@ -52,22 +52,61 @@ QueueHandle_t timerEinkQueue; QueueHandle_t timerAlarmQueue; QueueHandle_t alarmQueue; +void copybits(uint8_t *dest, + int dst_bit_offset, + const uint8_t *src, + int src_bit_offset, + int bit_length) +{ + for (int i = 0; i < bit_length; i++) { + // --- Read a single bit from src --- + int bit_idx_src = src_bit_offset + i; + int byte_idx_src = bit_idx_src / 8; + int bit_in_src = bit_idx_src % 8; + // extract MSB-first + uint8_t bit = (src[byte_idx_src] >> (7 - bit_in_src)) & 1; + + // --- Write that bit into dest --- + int bit_idx_dst = dst_bit_offset + i; + int byte_idx_dst = bit_idx_dst / 8; + int bit_in_dst = bit_idx_dst % 8; + uint8_t mask = 1u << (7 - bit_in_dst); + + // clear the destination bit and OR in our new bit + dest[byte_idx_dst] = (dest[byte_idx_dst] & ~mask) + | (bit << (7 - bit_in_dst)); + } +} + void draw_char(uint8_t *image, int x, int y, char c) { - uint32_t char_offset = (c - '0') * 16 * 176; + uint32_t char_offset = (c - '0') * 2816; + for(int i=0; i<176; ++i) { - memcpy(&image[x + (y+i)*EPD_WIDTH/8], &OverpassMono_Bitmaps[i*16+char_offset], 16); + int length = 128; + int dst_offset = x; + int src_offset = 0; + + if(dst_offset < 0) { + length += dst_offset; + src_offset = -dst_offset; + dst_offset = 0; + } + if(dst_offset + length > EPD_WIDTH) { + length = EPD_WIDTH - dst_offset; + } + if(length < 0) continue; + copybits(&image[(y+i)*EPD_WIDTH/8], dst_offset, &OverpassMono_Bitmaps[char_offset+i*16], src_offset, length); } } void draw_text(uint8_t *image, int x, int y, const char *text, int length) { - //89x130 for(int i=0; i '9') { ESP_LOGE(TAG, "Invalid character '%c' in text: %s", text[i], text); return; } - draw_char(image, x + i * 17, y, text[i]); + draw_char(image, x + i*136, y, text[i]); } } @@ -79,22 +118,43 @@ void eink_task(void *pvParameter) epd7in5_v3_t epd; epd7in5_v3_create(&epd, SPI2_HOST); - while(true) { + int x = 0; + int max_x = EPD_WIDTH - 536; + int y = 0; + int max_y = EPD_HEIGHT - 176; - // Wait for time update from timerQueue + int move_x = 10; + int move_y = 10; + + while(true) { TimerEvent event; if (xQueueReceive(timerEinkQueue, &event, portMAX_DELAY) != pdTRUE) { ESP_LOGE(TAG, "Failed to receive timer event from queue"); continue; } + x += move_x; + y += move_y; + if (x <= 0 || x >= max_x - 1) { + move_x = -move_x; + x = (x < 0) ? 0 : max_x - 1; + } + if (y <= 0 || y >= max_y - 1) { + move_y = -move_y; + y = (y < 0) ? 0 : max_y - 1; + } + char buffer[5] = {0}; memcpy(buffer, &event.time, sizeof(event.time)); memset(image, 0x00, sizeof(image)); - epd7in5_v3_init(&epd); - draw_text(image, 0, 0, buffer, 4); + if (buffer[3] == '0') { + epd7in5_v3_init(&epd); + } else { + epd7in5_v3_init_fast(&epd); + } + draw_text(image, x, y, buffer, 4); epd7in5_v3_busy_wait(&epd); epd7in5_v3_display(&epd, image); epd7in5_v3_busy_wait(&epd); @@ -121,6 +181,8 @@ void radio_task(void *pvParameter) { bool radioActive = false; + int volume = 25; + i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM, I2S_ROLE_MASTER); ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle, NULL)); @@ -171,6 +233,12 @@ void radio_task(void *pvParameter) AlarmEvent event; while(true) { if(!radioActive) { + //write 0 + memset(samples, 0, BUFFER_SAMPLES * sizeof(int16_t)); + size_t bytes_to_write = BUFFER_SAMPLES * sizeof(int16_t); + size_t bytes_written = 0; + ESP_ERROR_CHECK(i2s_channel_write(tx_handle, samples, bytes_to_write, &bytes_written, portMAX_DELAY)); + if(xQueueReceive(alarmQueue, &event, portMAX_DELAY) && event.event_id == 1) { ESP_LOGI(TAG, "Alarm activated, starting radio"); radioActive = true; @@ -184,7 +252,7 @@ void radio_task(void *pvParameter) //Do radio shit for (int i = 0; i < BUFFER_SAMPLES; ++i) { int16_t sample = level_up[(i+offset) % level_up_size]; - samples[i] = sample / 4; + samples[i] = (uint16_t)(((uint32_t)sample) * volume / 100); } size_t bytes_to_write = BUFFER_SAMPLES * sizeof(int16_t); @@ -203,8 +271,8 @@ void alarm_task(void *pvParameter) { bool alarmActive = false; - int alarmStart = 830; // 20:55 in HHMM format - int alarmEnd = 900; // 20:56 in HHMM format + int alarmStart = 830; + int alarmEnd = 900; TimerEvent event; while(true) {