使用dma模式搬运数据,需要打上如下补丁:
ledc在dma模式的代码存在问题,已修复该问题,ledc的dma通道之前也没有支持,需要添加上
diff --git a/hal/source/dma/platform/dma-sun8iw20.h b/hal/source/dma/platform/dma-sun8iw20.h
index 2140014..fc5c72e 100644
--- a/hal/source/dma/platform/dma-sun8iw20.h
+++ b/hal/source/dma/platform/dma-sun8iw20.h
@@ -136,6 +136,7 @@
#define DRQDST_OTG_EP3 32
#define DRQDST_OTG_EP4 33
#define DRQDST_OTG_EP5 34
+#define DRQDST_LEDC 42
#define DRQDST_TWI0_TX 43
#define DRQDST_TWI1_TX 44
#define DRQDST_TWI2_TX 45
diff --git a/hal/source/ledc/hal_ledc.c b/hal/source/ledc/hal_ledc.c
index 5499452..ddf471f 100755
--- a/hal/source/ledc/hal_ledc.c
+++ b/hal/source/ledc/hal_ledc.c
@@ -20,9 +20,10 @@
#define led_err(fmt, args...) printf("%s()%d - "fmt, __func__, __LINE__, ##args)
#define LEDC_PIN_SLEEP 0
+#define LEDC_DMA_BUF_SIZE 4096
struct ledc_config ledc_config = {
- .led_count = 3,
+ .led_count = 1024,
.reset_ns = 84,
.t1h_ns = 800,
.t1l_ns = 450,
@@ -37,6 +38,7 @@
static unsigned long base_addr = LEDC_BASE;
struct sunxi_dma_chan *dma_chan;
struct sunxi_led *led;
+static uint8_t already_init;
static hal_irqreturn_t sunxi_ledc_irq_handler(void *dummy)
{
@@ -448,15 +450,16 @@
void hal_ledc_dma_callback(void *para)
{
- printf("dma callback\n");
+ ledc_info("dma transfer end\n");
}
-void hal_ledc_trans_data(struct ledc_config *ledc)
+int hal_ledc_trans_data(struct ledc_config *ledc)
{
- int i;
+ int i, ret;
unsigned long int size;
unsigned int mask = 0;
struct dma_slave_config slave_config;
+ unsigned int const *buf = ledc->data;
mask = LEDC_TRANS_FINISH_INT_EN | LEDC_WAITDATA_TIMEOUT_INT_EN
| LEDC_FIFO_OVERFLOW_INT_EN | LEDC_GLOBAL_INT_EN;
@@ -480,23 +483,32 @@
ledc_reset_en();
size = ledc->length * 4;
+ if (size <= LEDC_DMA_BUF_SIZE) {
+ memcpy(ledc->align_dma_buf, buf, ledc->length);
+ buf = ledc->align_dma_buf;
+ }
- hal_dcache_clean((unsigned long)ledc->data, sizeof(ledc->data));
+ hal_dcache_clean((unsigned long)buf, size);
slave_config.direction = DMA_MEM_TO_DEV;
- slave_config.src_addr = (unsigned long)(ledc->data);
+ slave_config.src_addr = (unsigned long)buf;
slave_config.dst_addr = (uint32_t)(base_addr + LEDC_DATA_REG);
slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- slave_config.src_maxburst = DMA_SLAVE_BURST_16;
- slave_config.dst_maxburst = DMA_SLAVE_BURST_16;
+ slave_config.src_maxburst = DMA_SLAVE_BURST_4;
+ slave_config.dst_maxburst = DMA_SLAVE_BURST_4;
slave_config.slave_id = sunxi_slave_id(DRQDST_LEDC, DRQSRC_SDRAM);
- hal_dma_slave_config(dma_chan, &slave_config);
+ ret = hal_dma_slave_config(dma_chan, &slave_config);
+ if (ret) {
+ led_err("dma slave config failed\n");
+ return -1;
+ }
- hal_dma_prep_device(dma_chan, slave_config.dst_addr, slave_config.src_addr, size, DMA_MEM_TO_DEV);
-
- //dma_chan->callback = ledc_dma_callback;
- hal_dma_start(dma_chan);
+ ret = hal_dma_prep_device(dma_chan, slave_config.dst_addr, slave_config.src_addr, size, DMA_MEM_TO_DEV);
+ if (ret) {
+ led_err("dma prep device failed\n");
+ return -1;
+ }
hal_ledc_set_time(ledc);
ledc_set_output_mode(ledc->output_mode);
@@ -504,7 +516,15 @@
ledc_set_dma_mode();
ledc_enable_irq(mask);
ledc_enable();
+
+ dma_chan->callback = hal_ledc_dma_callback;
+ ret = hal_dma_start(dma_chan);
+ if (ret) {
+ led_err("dma start trans failed\n");
+ return -1;
+ }
}
+ return 0;
}
void hal_ledc_clear_all_irq(void)
@@ -598,6 +618,14 @@
int hal_ledc_init(void)
{
+ if (already_init) {
+ already_init++;
+ ledc_info("ledc has been inited, return ok\n");
+ return 0;
+ }
+
+ int ret, i;
+
ledc_info("hal_led_init\n");
led = malloc(sizeof(struct sunxi_led));
@@ -611,25 +639,40 @@
led->config.data = malloc(sizeof(unsigned int) * led->config.led_count);
if (NULL == led->config.data) {
led_err("sunxi led config data malloc err\n");
- goto err1;
+ goto err0;
}
+ for(i = 0;i < led->config.led_count;i++)
+ led->config.data[i] = 0;
if (ledc_clk_init())
{
led_err("ledc clk init failed \n");
+ goto err1;
}
if (ledc_pinctrl_init())
{
led_err("ledc pinctrl init failed \n");
+ goto err2;
}
- hal_dma_chan_request(&dma_chan);
+ ret = hal_dma_chan_request(&dma_chan);
+ if (ret == HAL_DMA_CHAN_STATUS_BUSY)
+ {
+ led_err("request dma_chan failed\n");
+ goto err3;
+ }
+ led->config.align_dma_buf = dma_alloc_coherent(LEDC_DMA_BUF_SIZE);
+ if (!led->config.align_dma_buf)
+ {
+ led_err("alloc dma memory failed\n");
+ goto err4;
+ }
if (hal_request_irq(SUNXI_IRQ_LEDC, sunxi_ledc_irq_handler, "ledc", led) < 0)
{
led_err("ledc request irq failed \n");
- goto errirq;
+ goto err5;
}
hal_enable_irq(SUNXI_IRQ_LEDC);
@@ -638,13 +681,22 @@
pm_devops_register(&pm_ledc);
#endif
+ already_init++;
ledc_info("hal_led_init success\n");
return 0;
-errirq:
- free(led->config.data);
+err5:
+ dma_free_coherent(led->config.align_dma_buf);
+err4:
+ hal_dma_chan_free(dma_chan);
+err3:
+ ledc_pinctrl_exit();
+err2:
+ ledc_clk_exit();
err1:
+ free(led->config.data);
+err0:
free(led);
return -1;
@@ -652,27 +704,35 @@
void hal_ledc_deinit(void)
{
+ if (already_init > 0) {
+ if (--already_init == 0) {
#ifdef CONFIG_COMPONENTS_PM
- pm_devops_unregister(&pm_ledc);
+ pm_devops_unregister(&pm_ledc);
#endif
- hal_disable_irq(SUNXI_IRQ_LEDC);
- hal_free_irq(SUNXI_IRQ_LEDC);
- hal_dma_chan_free(dma_chan);
- ledc_pinctrl_exit();
- ledc_clk_exit();
- free(led->config.data);
- free(led);
+ hal_disable_irq(SUNXI_IRQ_LEDC);
+ hal_free_irq(SUNXI_IRQ_LEDC);
+ dma_free_coherent(led->config.align_dma_buf);
+ hal_dma_chan_free(dma_chan);
+ ledc_pinctrl_exit();
+ ledc_clk_exit();
+ free(led->config.data);
+ free(led);
+ }
+ }
}
int sunxi_set_all_led(unsigned int brightness)
{
- int i;
+ int i, ret;
led->config.length = led->config.led_count;
for(i = 0;i < led->config.led_count;i++)
led->config.data[i] = brightness;
- hal_ledc_trans_data(&led->config);
+ ret = hal_ledc_trans_data(&led->config);
+ if (ret) {
+ led_err("ledc trans data error\n");
+ }
return 0;
}
@@ -680,6 +740,7 @@
int sunxi_set_led_brightness(int led_num, unsigned int brightness)
{
u32 reg_val;
+ int i, ret;
if (NULL == led) {
led_err("err : ledc is not init\n");
@@ -691,10 +752,16 @@
return -1;
}
- led->config.length = 1;
+ led->config.length = led_num;
led->config.data[led_num-1] = brightness;
- hal_ledc_trans_data(&led->config);
+ for (i = 0; i < led_num; i++)
+ ledc_info("the %d led light is %u\n", i + 1, led->config.data[i]);
+
+ ret = hal_ledc_trans_data(&led->config);
+ if (ret) {
+ led_err("ledc trans data error\n");
+ }
reg_val = hal_ledc_get_irq_status();
ledc_info("ledc interrupt status reg is %x", reg_val);
diff --git a/hal/source/ledc/platform_ledc.h b/hal/source/ledc/platform_ledc.h
index 39f6933..2fa9c38 100644
--- a/hal/source/ledc/platform_ledc.h
+++ b/hal/source/ledc/platform_ledc.h
@@ -33,8 +33,6 @@
#ifndef __PLATFORM_LEDC_H__
#define __PLATFORM_LEDC_H__
-#define DRQDST_LEDC 43
-
#if defined(CONFIG_ARCH_SUN8IW18P1)
#include "platform/ledc_sun8iw18.h"
#endif
diff --git a/hal/test/ledc/test_ledc.c b/hal/test/ledc/test_ledc.c
index 1ade796..79694c0 100755
--- a/hal/test/ledc/test_ledc.c
+++ b/hal/test/ledc/test_ledc.c
@@ -20,6 +20,7 @@
int ledc_test(int argc, char **argv)
{
int brightness = 0;
+ int led_num;
printf("========LEDC TEST========\n");
@@ -32,9 +33,14 @@
return 0;
}
- brightness = atoi(argv[2]);
+ led_num = atoi(argv[1]);
+ if (led_num < 1 || led_num > 1024)
+ {
+ printf("The led_num you entered should be between 1 and 1024\n");
+ }
+ brightness = atoi(argv[3]);
- switch(argv[1][0])
+ switch(argv[2][0])
{
case 'R' : brightness <<= 8; break;
case 'G' : brightness <<= 16; break;
@@ -43,7 +49,8 @@
return -1;
}
- sunxi_set_led_brightness(1, brightness);
+ sunxi_set_led_brightness(led_num, brightness);
+ printf("led is %d\n", led_num);
printf("brightness is %d\n", brightness);
return 0;
diff --git a/include/hal/sunxi_hal_ledc.h b/include/hal/sunxi_hal_ledc.h
index a386338..e5a70d1 100644
--- a/include/hal/sunxi_hal_ledc.h
+++ b/include/hal/sunxi_hal_ledc.h
@@ -43,6 +43,7 @@
unsigned long long wait_time1_ns;
unsigned int wait_data_time_ns;
char *output_mode;
+ unsigned int *align_dma_buf;
unsigned int *data;
unsigned int length;
};
@@ -86,7 +87,7 @@
int hal_ledc_init(void);
void hal_ledc_deinit(void);
-void hal_ledc_trans_data(struct ledc_config *ledc);
+int hal_ledc_trans_data(struct ledc_config *ledc);
void hal_ledc_clear_all_irq(void);
unsigned int hal_ledc_get_irq_status(void);
void hal_ledc_dma_callback(void *para);
DMA下 LED 颜色异常
diff --git a/hal/source/ledc/hal_ledc.c b/hal/source/ledc/hal_ledc.c
index ddf471f4..8d818662 100755
--- a/hal/source/ledc/hal_ledc.c
+++ b/hal/source/ledc/hal_ledc.c
@@ -308,11 +308,15 @@ static void ledc_set_wait_data_time_ns(unsigned int wait_data_time_ns)
hal_writel(reg_val, base_addr + LEDC_DATA_FINISH_CNT_REG);
}
+/*
+ * set the num of leds on the led-strip
+ * max support up to 1024 leds
+ */
static void ledc_set_length(unsigned int length)
{
unsigned int reg_val;
- if (length == 0)
+ if (length == 0 || length > 1024)
return;
reg_val = hal_readl(base_addr + LEDC_CTRL_REG);
@@ -721,12 +725,22 @@ void hal_ledc_deinit(void)
}
}
-int sunxi_set_all_led(unsigned int brightness)
+/*
+ * set the brightness of all the leds in led-strip to a uniform value
+ * @length: the num of leds on led-strip
+ * @brightness: the brightness data
+ */
+int sunxi_set_all_led(unsigned int length, unsigned int brightness)
{
int i, ret;
- led->config.length = led->config.led_count;
- for(i = 0;i < led->config.led_count;i++)
+ if (length > led->config.led_count) {
+ led_err("%d: max support 1024 leds\n", length);
+ return -1;
+ }
+
+ led->config.length = length;
+ for(i = 0;i < led->length;i++)
led->config.data[i] = brightness;
ret = hal_ledc_trans_data(&led->config);
@@ -737,7 +751,13 @@ int sunxi_set_all_led(unsigned int brightness)
return 0;
}
-int sunxi_set_led_brightness(int led_num, unsigned int brightness)
+/*
+ * set the brightness of each led on the led strip
+ * @length: all the num of leds on the led strip
+ * @led_num: the specified led that you want to set
+ * @brightness: the led brightness data
+ */
+int sunxi_set_led_brightness(unsigned int length, unsigned int led_num, unsigned int brightness)
{
u32 reg_val;
int i, ret;
@@ -747,12 +767,13 @@ int sunxi_set_led_brightness(int led_num, unsigned int brightness)
return -1;
}
- if (led_num > led->config.led_count) {
+ if (length > led->config.led_count || len_num > length) {
led_err("has not the %d led\n", led_num);
return -1;
}
- led->config.length = led_num;
+ led->config.length = length;
+ /* set the specified led brightness, others set default brightness: 0x0*/
led->config.data[led_num-1] = brightness;
for (i = 0; i < led_num; i++)