Browse Source

Initial commit, port code from esp8266

Helmut Pozimski 4 years ago
commit
4c9ee28769
8 changed files with 336 additions and 0 deletions
  1. 3 0
      .gitignore
  2. 6 0
      CMakeLists.txt
  3. 9 0
      Makefile
  4. 5 0
      README.md
  5. 4 0
      main/CMakeLists.txt
  6. 5 0
      main/component.mk
  7. 8 0
      main/configuration.h
  8. 296 0
      main/transmit_i2s.c

+ 3 - 0
.gitignore

@@ -0,0 +1,3 @@
+sdkconfig
+build
+wifi_credentials.h

+ 6 - 0
CMakeLists.txt

@@ -0,0 +1,6 @@
+# The following lines of boilerplate have to be in your project's
+# CMakeLists in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(esp32-transmit-i2s)

+ 9 - 0
Makefile

@@ -0,0 +1,9 @@
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := esp32-transmit-i2s
+
+include $(IDF_PATH)/make/project.mk
+

+ 5 - 0
README.md

@@ -0,0 +1,5 @@
+# Hello World Example
+
+Starts a FreeRTOS task to print "Hello World"
+
+See the README.md file in the upper level 'examples' directory for more information about examples.

+ 4 - 0
main/CMakeLists.txt

@@ -0,0 +1,4 @@
+set(COMPONENT_SRCS "transmit_i2s.c")
+set(COMPONENT_ADD_INCLUDEDIRS "")
+
+register_component()

+ 5 - 0
main/component.mk

@@ -0,0 +1,5 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
+

+ 8 - 0
main/configuration.h

@@ -0,0 +1,8 @@
+/*
+ * SPDX-FileCopyrightText: 2019 Helmut Pozimski <helmut@pozimski.eu>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+#define SAMPLE_RATE 8000
+#define TARGET_HOST "10.0.0.1"
+#define TARGET_PORT 8000

+ 296 - 0
main/transmit_i2s.c

@@ -0,0 +1,296 @@
+/*
+ * SPDX-FileCopyrightText: 2019 Helmut Pozimski <helmut@pozimski.eu>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+#include <freertos/FreeRTOS.h>
+#include <freertos/event_groups.h>
+
+#include <esp_event.h>
+#include <esp_wifi.h>
+#include <esp_log.h>
+#include <esp_event_loop.h>
+
+#include <driver/gpio.h>
+#include <driver/i2s.h>
+#include <lwip/sockets.h>
+#include <soc/io_mux_reg.h>
+#include <nvs_flash.h>
+
+#include <string.h>
+
+#include "wifi_credentials.h"
+#include "configuration.h"
+
+#define WIFI_LOG_PREFIX "Wifi"
+#define TCP_LOG_PREFIX "TCP"
+
+// Mapping of board pins to the functions they are used for
+#define MD1 16
+#define MD0 17
+#define MD 18
+#define MC 19
+#define MS 21
+
+#define SLAVE_DATA_IN 27
+#define SLAVE_BCK_IN 26
+#define SLAVE_WS_IN 25
+
+#define GPIO_OUTPUT_PIN_SEL ((1ULL<<MD0) |(1ULL<<MD1) | (1ULL<<MD) | (1ULL<<MC) | (1ULL<<MS))
+
+#define gpio_set(x,y) ESP_ERROR_CHECK(gpio_set_level(x,y))
+
+/* Bit sequence to send to the clock generator */
+
+#if SAMPLE_RATE == 8000
+static uint16_t pll_seq = 21518;
+#elif SAMPLE_RATE == 16000
+static uint16_t pll_seq = 17422;
+#elif SAMPLE_RATE == 32000
+static uint16_t pll_seq = 25614;
+#elif SAMPLE_RATE == 44100
+static uint16_t pll_seq = 41998;
+#elif SAMPLE_RATE == 48000
+static uint16_t pll_seq = 9230;
+#endif
+
+/* Event group for Wifi events */
+static EventGroupHandle_t wifi_event_group;
+
+/* Bit to signal that a connection to the AP has been establisched */
+const int WIFI_CONNECTED_BIT = BIT0 ;
+
+/* Structures to handle synchronisation with the server */
+typedef struct {
+        uint32_t sample_rate;
+        uint32_t bits_per_sample;
+} sync;
+
+typedef struct {
+        char ack[4];
+        sync dat;
+} sync_ack;
+
+/*
+ * Function: wifi_event_handler
+ * ----------------------------
+ *   Callback function that handles wifi events
+ * 
+ *   ctx: context from which the function was called
+ *   event: event that occured and should be handled
+ *
+ *   returns: an error code
+ */
+static esp_err_t wifi_event_handler(void *ctx, system_event_t *event) {
+	ESP_LOGI(WIFI_LOG_PREFIX, "Event handler called");
+	if (event->event_id == SYSTEM_EVENT_STA_START) {
+		ESP_LOGI(WIFI_LOG_PREFIX, "Wifi connection started");
+		esp_wifi_connect();
+	} else if (event->event_id == SYSTEM_EVENT_STA_GOT_IP) {
+		ESP_LOGI(WIFI_LOG_PREFIX, "Acquired IP address: %s",
+		ip4addr_ntoa (&event->event_info.got_ip.ip_info.ip));
+		xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_BIT);
+	} else if (event->event_id == SYSTEM_EVENT_STA_DISCONNECTED) {
+		ESP_LOGI(WIFI_LOG_PREFIX, "Connection lost");
+		esp_wifi_connect();
+		xEventGroupClearBits(wifi_event_group, WIFI_CONNECTED_BIT);
+	}
+	return ESP_OK;
+}	
+
+/*
+ * Function: configure_wifi
+ * ------------------------ 
+ *   Configures the necessary parameters to establish a wifi connection
+ */
+static void configure_wifi(void) {
+	wifi_event_group = xEventGroupCreate();
+	tcpip_adapter_init();
+	ESP_ERROR_CHECK(esp_event_loop_init(wifi_event_handler, NULL));
+	wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+	ESP_ERROR_CHECK(esp_wifi_init(&cfg));
+	ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
+	wifi_config_t wifi_config = {
+		.sta = {
+			.ssid = WIFI_AP,
+			.password = WIFI_WPA_KEY
+		},
+	};
+	ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
+	ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
+	ESP_ERROR_CHECK(esp_wifi_set_protocol(ESP_IF_WIFI_STA, WIFI_PROTOCOL_11B |
+			WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N));
+	ESP_ERROR_CHECK(esp_wifi_set_bandwidth(ESP_IF_WIFI_STA, WIFI_BW_HT40));
+	ESP_ERROR_CHECK(esp_wifi_start());
+}
+
+/*
+ * Function: setup_gpio
+ * --------------------
+ *     Configures the GPIO Pins that are used
+ *
+ * returns: error code of the configuration operation
+ */
+static esp_err_t setup_gpio(void) {
+	esp_err_t gpio_err;
+	PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO16_U, FUNC_GPIO16_GPIO16);
+	PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U, FUNC_GPIO17_GPIO17);
+	PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO18_U, FUNC_GPIO18_GPIO18);
+	PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, FUNC_GPIO19_GPIO19);
+	PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO21_U, FUNC_GPIO21_GPIO21);
+	gpio_config_t io_conf = {
+		.intr_type = GPIO_INTR_DISABLE,
+		.mode = GPIO_MODE_OUTPUT,
+		.pin_bit_mask = GPIO_OUTPUT_PIN_SEL,
+		.pull_down_en = 0,
+		.pull_up_en = 0,
+	};
+	gpio_err = gpio_config(&io_conf);
+	return gpio_err;
+}
+
+/*
+ * Function pcm1808_config
+ * --------------------------
+ *     Sets the MD0 and MD1 inputs for the pcm1808
+ *
+ * md1: value for input md1
+ * md0: value for input md0
+ */
+static void pcm1808_config(uint32_t md1, uint32_t md0) {
+	gpio_set(MD1, md1);
+	gpio_set(MD0, md0); 
+}
+
+/* Function send_pll_bits
+ * ----------------------
+ *     Sends a bit sequence to configure the PLL1708
+ * 
+ * bits: 16 bit unsigned integer representing the bits to be send from right to left
+ */
+static void send_pll_bits(uint16_t bits) {
+	gpio_set(MS,0);
+	gpio_set(MC,0);
+	for (uint8_t i=16; i>0; i--) {
+		vTaskDelay(100 / portTICK_PERIOD_MS);
+		gpio_set(MD, bits & 1);
+		bits = bits >>1;
+		gpio_set(MC, 1);
+		vTaskDelay(100 / portTICK_PERIOD_MS);
+		gpio_set(MC, 0);	
+	}
+	gpio_set(MS,1);
+}
+
+/*
+ * Function: setup_i2s
+ * -------------------
+ *     Initializes the i2s driver with the proper configuration
+ */
+static void setup_i2s(void) {
+	i2s_config_t i2s_config = {
+		.mode = I2S_MODE_SLAVE | I2S_MODE_RX,
+		.sample_rate = SAMPLE_RATE,
+		.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
+		.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
+		.communication_format = I2S_COMM_FORMAT_I2S,
+		.dma_buf_count = 35,
+		.dma_buf_len = 256
+	};
+	i2s_pin_config_t pin_config = {
+		.bck_io_num = SLAVE_BCK_IN,
+		.ws_io_num = SLAVE_WS_IN,
+		.data_in_num = SLAVE_DATA_IN,
+		.data_out_num = I2S_PIN_NO_CHANGE
+	};
+	ESP_ERROR_CHECK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL));
+	ESP_ERROR_CHECK(i2s_set_pin(I2S_NUM_0, &pin_config));
+}
+
+/*
+ * Function: transmit_task
+ *     Function that reads values from i2s and transmits them via TCP, it represents the main task
+ *
+ * pvParameters: parameters passed to the task
+ */
+static void transmit_task(void *pvParameters) {
+	send_pll_bits(pll_seq);
+	struct sockaddr_in dest_addr;
+	dest_addr.sin_addr.s_addr = inet_addr(TARGET_HOST);
+	dest_addr.sin_family = AF_INET;
+	dest_addr.sin_port = htons(TARGET_PORT);
+	int sock = 0;
+	void *transmit_buffer = malloc(1458);
+	if (transmit_buffer == NULL) {
+		ESP_LOGE("MALLOC", "Could not allocate memory for data buffer");
+	}
+	uint16_t offset = 0;
+	unsigned int bytes_read;
+	int err;
+	sync sync_data = {
+		.sample_rate = SAMPLE_RATE,
+		.bits_per_sample = 24
+	};
+	sync_ack ack;
+	while (1) {
+		if (sock != 0) {
+			close(sock);
+		}
+		sock = socket(dest_addr.sin_family, SOCK_STREAM, IPPROTO_IP);
+		if (sock < 0) {
+			ESP_LOGE(TCP_LOG_PREFIX, "Could not create socket");
+			continue;
+		}
+		xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_BIT, false, true, portMAX_DELAY);
+		ESP_LOGI(TCP_LOG_PREFIX, "Establishing connection");
+		err = connect(sock, (struct sockaddr*)&dest_addr, sizeof(dest_addr));
+		if (err != 0) {
+			ESP_LOGE(TCP_LOG_PREFIX, "Failed to establish a TCP connection");
+			continue;
+		}
+		send(sock, &sync_data, sizeof(sync_data), 0);
+		recv(sock, &ack, sizeof(ack), 0);
+		if ((strcmp(ack.ack, "ACK") !=0) || (ack.dat.sample_rate != SAMPLE_RATE) || (ack.dat.bits_per_sample != 24)) {
+			ESP_LOGE(TCP_LOG_PREFIX, "Synchronisation with server not successful");
+			continue;
+		}
+		ESP_LOGI(TCP_LOG_PREFIX, "Connection successfully established");
+		uint8_t discard;
+		while (1) {
+			if (offset < 1458) {
+				i2s_read(I2S_NUM_0, transmit_buffer + offset, 3, &bytes_read, portMAX_DELAY);
+				offset += 3;
+				i2s_read(I2S_NUM_0, &discard, 1, &bytes_read, portMAX_DELAY);
+			}
+			if (offset == 1458) {
+				err = send(sock, transmit_buffer, 1458, 0);
+				if (err < 0) {
+					ESP_LOGE(TCP_LOG_PREFIX, "TCP connection lost");
+					break;
+				}
+				offset = 0;
+			}
+		}
+	}
+	vTaskDelete(NULL);
+}
+
+/*
+ * Function: app_main
+ * ------------------
+ *     Entry function that sets up the main task and initializes everything
+ */
+void app_main(void) {
+	ESP_ERROR_CHECK(nvs_flash_init());
+	configure_wifi();
+	xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_BIT, false, true, portMAX_DELAY);
+	// Initialize GPIO pins
+	ESP_ERROR_CHECK(setup_gpio());
+	// Set PCM1808 configuration
+	pcm1808_config(0, 1);
+	// Power down PLL1708
+	send_pll_bits(40974);
+	// Initialize the i2s driver
+	setup_i2s();
+	xTaskCreate(transmit_task, "transmit_task", 4096, NULL, 7, NULL);
+}