Skip to content

FAQ:AD16 LEDC示例 #8

@ghost

Description

一、概述
AD16支持一路硬件LEDC对灯带进行驱动和控制,LEDC通过DMA数据传输,可通过配置可以使led灯带显示不同颜色变化。在使用之前需要将JL_LEDCK->CLK寄存器的[1-0]置0,然后在进行相关配置。否则可能出现异常。
二、示例驱动代码

typedef enum {          //由48M时钟源算出的时间单位
    t_21ns,
    t_42ns,
    t_63ns,
    t_125ns,
    t_250ns,
    t_500ns,
    t_1us,
    t_2us,
    t_4us,
} t_unit_enum;
        
struct ledc_platform_data {                                                                                                                                                                  
    u8 port;            //输出引脚
    u8 idle_level;      //当前帧的空闲电平,0:低电平, 1:高电平
    u8 out_inv;         //起始电平,0:高电平开始, 1:低电平开始
    u8 bit_inv;         //取数据时高低位镜像,0:不镜像,1:8位镜像,2:16位镜像,3:32位镜像
    t_unit_enum t_unit; //时间单位
    u8 t1h_cnt;         //1码的高电平时间 = t1h_cnt * t_unit;
    u8 t1l_cnt;         //1码的低电平时间 = t1l_cnt * t_unit;
    u8 t0h_cnt;         //0码的高电平时间 = t0h_cnt * t_unit;
    u8 t0l_cnt;         //0码的低电平时间 = t0l_cnt * t_unit;
    u32 t_rest_cnt;     //复位信号时间 = t_rest_cnt * t_unit;
    void (*cbfun)(void);//中断回调函数
};   
        
        
#define LEDC_PLATFORM_DATA_BEGIN(data) \
    const struct ledc_platform_data data = {
        
#define LEDC_PLATFORM_DATA_END()  \
};

static void (*ledc_isr_cbfun)(void) = NULL;
volatile u8 ledc_busy = 0;              
___interrupt                            
void ledc_isr(void)                     
{                                       
    if (JL_LEDC->CON & BIT(7)) {        //PND
        JL_LEDC->CON |= BIT(6);         //CPND
        if (ledc_isr_cbfun) {           
            ledc_isr_cbfun();           
        }                               
    }                                   
    ledc_busy = 0;                      
}                                       
                                        
static u8 t_div[9] = {1, 2, 3, 6, 12, 24, 48, 96, 192};                                                                                                                                      
void ledc_init(const struct ledc_platform_data *arg)
{                                       
    gpio_set_die(arg->port, 1);         
    gpio_set_direction(arg->port, 0); 
    gpio_set_pull_up(arg->port, 0);  
    gpio_set_pull_down(arg->port, 0); 
    gpio_och_sel_output_signal(arg->port, OUTPUT_CH_SIGNAL_GP_LEDC);  //OUTPUT_CHANNEL自动分配
                                        
    //std_48M                           
    JL_LEDCK->CLK &= ~(0b11 << 0);   
    JL_LEDCK->CLK |= (0b10 << 0);       
    //set div                           
    JL_LEDCK->CLK &= ~(0xff << 8);   
    JL_LEDCK->CLK |= ((t_div[arg->t_unit] - 1) << 8); 
                                        
    JL_LEDC->CON = BIT(6);  //CPND   
                                        
    if (arg->cbfun) {           //异步工作方式,建议用于传输数据量较大的应用
        JL_LEDC->CON |= BIT(5); //IE
        request_irq(IRQ_LEDC_IDX, IRQ_LEDC_IP, ledc_isr, 0);
        ledc_isr_cbfun = arg->cbfun; 
    }                                
                                     
    if (arg->idle_level) {           
        JL_LEDC->CON |= BIT(4);      
    }                                
    if (arg->out_inv) {              
        JL_LEDC->CON |= BIT(3);      
    }                                
                                     
    JL_LEDC->CON |= (arg->bit_inv << 1);                                                                                                                                                     
 
/**********配置信号高低电平时间*******/                                   
    JL_LEDC->TIX = 0;                
    JL_LEDC->TIX |= ((arg->t1h_cnt - 1) << 24);    //输出1码高电平时间,单位CNT_CK,实际值减1
    JL_LEDC->TIX |= ((arg->t1l_cnt - 1) << 16);    //输出1码低电平时间,单位CNT_CK,实际值减1
    JL_LEDC->TIX |= ((arg->t0h_cnt - 1) << 8);     //输出0码高电平时间,单位CNT_CK,实际值减1
    JL_LEDC->TIX |= ((arg->t0l_cnt - 1) << 0);     //输出0码低电平时间,单位CNT_CK,实际值减1
/************************************/
                                    
    JL_LEDC->RSTX = 0;               
    JL_LEDC->RSTX |= (arg->t_rest_cnt << 8);      //每一帧开始复位有效时间长度,单位CNT_CK
                                     
    log_info("JL_LEDCK->CLK = 0x%x\n", JL_LEDCK->CLK);
    log_info("JL_LEDC->CON = 0x%x\n", JL_LEDC->CON);
    log_info("JL_LEDC->TIX = 0x%x\n", JL_LEDC->TIX);
    log_info("JL_LEDC->RSTX = 0x%x\n", JL_LEDC->RSTX);
}

void ledc_send_rgbbuf(u8 *rgbbuf, u32 buf_len, u16 again_cnt)
{                                  
    if (JL_LEDC->CON & BIT(5)) {     //用于异步工作方式,防止数据重入
        while (ledc_busy);          
    }                              
    JL_LEDC->ADR = (u32)rgbbuf;     
    JL_LEDC->FD = buf_len * 8;       //FD_LEN RGB灯配置为灯数量n*3*8,即为不重复n个LED数据循环
    JL_LEDC->LP = again_cnt;         //FD_LEN重复次数,即将JL_LEDC->FD的数据在一次循环中重复发送,0则不重复
    ledc_busy = 1;                   //防止打断上一次发送的数据,用于异步工作方式
    JL_LEDC->CON |= BIT(0);          //启动   
    if (!(JL_LEDC->CON & BIT(5))) {  //用于同步工作方式(无中断),建议用于发送数据量较少的应用                                                                                                                                                        
        while (!(JL_LEDC->CON & BIT(7)));
        JL_LEDC->CON |= BIT(6);     
    }                               
}                                   
#if 0                               
// *INDENT-OFF*                     
/*******************************    参考示例 ***********************************/
#define LED_NUM  10                 
static u8 ledc_test_buf[LED_NUM * 3] __attribute__((aligned(4))); //RGB灯数据BUF
static void ledc_callback()        
{                                  
    putchar('c');                  
}
LEDC_PLATFORM_DATA_BEGIN(ledc0_data)
    .port = IO_PORTA_04,           
    .idle_level = 0,               
    .out_inv = 0, 
    .bit_inv = 1,                  
    .t_unit = t_42ns,              
    .t1h_cnt = 24,
    .t1l_cnt = 7,                  
    .t0h_cnt = 7,                  
    .t0l_cnt = 24,                                                                                                                                                                           
    .t_rest_cnt = 200,             
    .cbfun = ledc_callback,        
LEDC_PLATFORM_DATA_END()           
                                   
void delay_10ms(u32 tick);         
void wdt_clear(void);              
void ledc_test(void)               
{                                  
    log_info("*************  ledc test  **************\n");
                                   
    ledc_init(&ledc0_data);        
                                   
    /* ledc_test_buf[0] = 0; */    
    /* ledc_test_buf[1] = 85; */   
    /* ledc_test_buf[2] = 170; */  
    for (u8 i = 0; i < sizeof(ledc_test_buf); i++) {
        ledc_test_buf[i] = (u8)rand();
    }             
    u16 again_cnt = 0;
    while (1) {   
        wdt_clear();
        for (u8 i = 0; i < sizeof(ledc_test_buf); i++) {
            ledc_test_buf[i] = (u8)rand();
        }
        ledc_send_rgbbuf(ledc_test_buf, sizeof(ledc_test_buf), again_cnt);
        delay_10ms(10);              
    }                                
}
#endif

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions