led_matrix/main/led_matrix.c

267 lines
8.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"
#include "esp_lcd_panel_io_i80_hub75.h"
#include "esp_lcd_panel_ops.h"
#include "driver/gpio.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_rom_sys.h"
#include "hal/ledc_hal.h"
#include "driver/ledc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/sens_reg.h"
#include "soc/rtc_periph.h"
#include "driver/rtc_io.h"
#include "ulp_riscv.h"
#include "ulp_main.h"
static const char *TAG = "led matrix";
#define HUB75_CLOCK_HZ (10 * 1000 * 1000)
#define HUB75_MAX_SCAN_TIMES (8) /* 扫描次数是8次也就是每一行会被扫8次用于全彩显示 */
#define HUB75_MAX_SCAN_LINE (8) /* 最多扫描行 */
#define HUB75_MAX_TRANSFER_DATA_NUM (128) /* 最多发送128个uint16数据 */
#define HUB75_MAX_TRANSFER_BUTES (HUB75_MAX_TRANSFER_DATA_NUM * 2)
#define HUB75_WIDTH (64)
#define HUB75_HEIGHT (32)
#define HUB75_LINE_ADDR_A_PIN_NUM 33
#define HUB75_LINE_ADDR_B_PIN_NUM 34
#define HUB75_LINE_ADDR_C_PIN_NUM 35
#define HUB75_LINE_ADDR_D_PIN_NUM 36
#define HUB75_LAT_PIN_NUM 8
#define HUB75_OE_PIN_NUM 21
#define HUB75_CLK_PIN_NUM 7
#define HUB75_OE_CAPTRUE_PIN_NUM 18
#define HUB75_OE_CAPTRUE__RTC_PIN_NUM GPIO_NUM_18
#define HUB75_LINE_ADDR_A_RTC_PIN_NUM GPIO_NUM_16
#define HUB75_LINE_ADDR_B_RTC_PIN_NUM GPIO_NUM_15
#define HUB75_LINE_ADDR_C_RTC_PIN_NUM GPIO_NUM_14
#define HUB75_LINE_ADDR_D_RTC_PIN_NUM GPIO_NUM_13
#define HUB75_G0 1
#define HUB75_R0 2
#define HUB75_B0 3
#define HUB75_G1 4
#define HUB75_R1 5
#define HUB75_B1 6
#define HUB75_G2 37
#define HUB75_R2 38
#define HUB75_B2 39
#define HUB75_G3 40
#define HUB75_R3 41
#define HUB75_B3 42
#define PSRAM_DATA_ALIGNMENT 64
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
esp_lcd_i80_hub75_bus_handle_t i80_bus = NULL;
esp_lcd_panel_io_handle_t io_handle = NULL;
static void led_matrix_i80_hub75_bus_init(void)
{
/* 8080总线配置 */
ESP_LOGI(TAG, "Initialize Intel 8080 bus");
esp_lcd_i80_hub75_bus_config_t bus_config = {
.clk_src = HUB75_CLK_PIN_NUM,
.wr_gpio_num = HUB75_CLK_PIN_NUM,
.data_gpio_nums = {
HUB75_R0,
HUB75_G0,
HUB75_B0,
HUB75_R1,
HUB75_G1,
HUB75_B1,
HUB75_R2,
HUB75_G2,
HUB75_B2,
HUB75_R3,
HUB75_G3,
HUB75_B3,
-1,
-1,
-1,
-1,
},
.bus_width = 16,
.max_transfer_bytes = HUB75_MAX_TRANSFER_BUTES, /* 每次发一行 */
.max_scan_line = HUB75_MAX_SCAN_LINE,
.max_scan_times = HUB75_MAX_SCAN_TIMES,
.height = HUB75_HEIGHT,
.width = HUB75_WIDTH,
.psram_trans_align = PSRAM_DATA_ALIGNMENT,
.sram_trans_align = 4,
};
ESP_ERROR_CHECK(esp_lcd_new_i80_hub75_bus(&bus_config, &i80_bus));
/* 8080IO设备申请 */
esp_lcd_panel_io_i80_hub75_config_t io_config = {
.cs_gpio_num = -1,
.pclk_hz = HUB75_CLOCK_HZ,
.trans_queue_depth = 10,
.flags = {
.pclk_idle_low = 1,
},
.on_color_trans_done = NULL,
.user_ctx = NULL,
.lcd_cmd_bits = 0,
.lcd_param_bits = 0,
};
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i80_hub75(i80_bus, &io_config, &io_handle));
}
#define LEDC_MODE LEDC_LOW_SPEED_MODE
#define LEDC_TIMER LEDC_TIMER_0
#define LEDC_DUTY_RES LEDC_TIMER_11_BIT
#define LEDC_FREQUENCY (60 * HUB75_MAX_SCAN_TIMES * HUB75_MAX_SCAN_LINE)
#define LEDC_DUTY_OE (1000) /* 先低后高,前面有效,控制亮度 */
#define LEDC_DUTY_LAT (2048 - 5) /* 高电平锁存 */
static void IRAM_ATTR ledc_timer_ovf_isr(void *arg);
extern esp_err_t ledc_set_timer_ovf_intr(ledc_mode_t speed_mode, ledc_channel_t channel, int enbale);
extern void ledc_clear_timer_ovf_intr_status(ledc_timer_t timer_num);
static ledc_isr_handle_t s_ledc_time_isr_handle = NULL;
static esp_err_t led_matrix_oe_lat_ledc_init(void)
{
ESP_LOGI(TAG, "led_matrix_oe_lat_ledc_init");
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_MODE,
.timer_num = LEDC_TIMER,
.duty_resolution = LEDC_DUTY_RES,
.freq_hz = LEDC_FREQUENCY,
.clk_cfg = LEDC_AUTO_CLK};
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
ledc_channel_config_t ledc_channel_oe = {
.speed_mode = LEDC_MODE,
.channel = LEDC_CHANNEL_0,
.timer_sel = LEDC_TIMER,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = HUB75_OE_PIN_NUM,
.duty = LEDC_DUTY_OE,
.flags.output_invert = 1,
.hpoint = 0};
ledc_channel_config_t ledc_channel_lat = {
.speed_mode = LEDC_MODE,
.channel = LEDC_CHANNEL_1,
.timer_sel = LEDC_TIMER,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = HUB75_LAT_PIN_NUM,
.duty = LEDC_DUTY_LAT,
.flags.output_invert = 1,
.hpoint = 0};
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel_oe));
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel_lat));
/* 中断配置 */
ledc_set_timer_ovf_intr(LEDC_MODE, LEDC_TIMER, false);
int isr_flags = ESP_INTR_FLAG_LEVEL2;
int ret = ledc_isr_register(ledc_timer_ovf_isr, i80_bus, isr_flags, &s_ledc_time_isr_handle);
ESP_GOTO_ON_ERROR(ret, err, TAG, "install interrupt failed");
ledc_set_timer_ovf_intr(LEDC_MODE, LEDC_TIMER, true);
return ESP_OK;
err:
return ESP_FAIL;
}
static int times = 0;
static int line = 0; /* 本次扫描行32行16扫一次显示两行 */
static void IRAM_ATTR ledc_timer_ovf_isr(void *arg)
{
ledc_clear_timer_ovf_intr_status(LEDC_TIMER_0);
line ++;
if (line == HUB75_MAX_SCAN_LINE)
{
line = 0;
times ++;
if (times == HUB75_MAX_SCAN_TIMES)
times = 0;
}
/* ULP处理行地址 */
ulp_line = line;
// if (ulp_flag != 0) ESP_LOGE(TAG, "ULP not deal line addr");
ulp_flag = 1;
hub75_send_line(io_handle, times, line);
}
extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start");
extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end");
static void led_matrix_ulp_risc_init(void)
{
ESP_LOGI(TAG, "led_matrix_ulp_risc_init");
rtc_gpio_init(HUB75_OE_CAPTRUE__RTC_PIN_NUM);
rtc_gpio_set_direction(HUB75_OE_CAPTRUE__RTC_PIN_NUM, RTC_GPIO_MODE_INPUT_ONLY);
rtc_gpio_pulldown_dis(HUB75_OE_CAPTRUE__RTC_PIN_NUM);
rtc_gpio_pullup_dis(HUB75_OE_CAPTRUE__RTC_PIN_NUM);
rtc_gpio_hold_en(HUB75_OE_CAPTRUE__RTC_PIN_NUM);
rtc_gpio_init(HUB75_LINE_ADDR_A_RTC_PIN_NUM);
rtc_gpio_set_direction(HUB75_LINE_ADDR_A_RTC_PIN_NUM, RTC_GPIO_MODE_OUTPUT_ONLY);
rtc_gpio_init(HUB75_LINE_ADDR_B_RTC_PIN_NUM);
rtc_gpio_set_direction(HUB75_LINE_ADDR_B_RTC_PIN_NUM, RTC_GPIO_MODE_OUTPUT_ONLY);
rtc_gpio_init(HUB75_LINE_ADDR_C_RTC_PIN_NUM);
rtc_gpio_set_direction(HUB75_LINE_ADDR_C_RTC_PIN_NUM, RTC_GPIO_MODE_OUTPUT_ONLY);
rtc_gpio_init(HUB75_LINE_ADDR_D_RTC_PIN_NUM);
rtc_gpio_set_direction(HUB75_LINE_ADDR_D_RTC_PIN_NUM, RTC_GPIO_MODE_OUTPUT_ONLY);
esp_err_t err = ulp_riscv_load_binary(ulp_main_bin_start, (ulp_main_bin_end - ulp_main_bin_start));
ESP_ERROR_CHECK(err);
ulp_set_wakeup_period(0, 20000);
/* Start the program */
err = ulp_riscv_run();
ESP_ERROR_CHECK(err);
}
void led_matrix_init(void)
{
ESP_LOGI(TAG, "led_matrix_init");
led_matrix_i80_hub75_bus_init();
led_matrix_oe_lat_ledc_init();
led_matrix_ulp_risc_init();
}
/* 设置亮度规定可调范围0-1800 */
int led_matrix_set_brightness(int brightness)
{
if (brightness < 0 || brightness > 1800)
{
ESP_LOGE(TAG, "Invalid brightness value(0-1800): %d", brightness);
return -1;
}
ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL_0, brightness));
ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL_0));
return 0;
}
/* 画点 */
int led_matrix_draw_point(int x, int y, uint8_t color)
{
return hub75_draw_point(io_handle, x, y, color);
}
/* 填充区域 */
void led_matrix_fill_rectangle(int x0, int y0, int x1, int y1, void *color)
{
hub75_fill_rectangle(io_handle, x0, y0, x1, y1, color);
}