/* * Copyright (c) 2017 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ /* * References: * * https://www.microbit.co.uk/device/screen * https://lancaster-university.github.io/microbit-docs/ubit/display/ */ #include #include #include #include #include #include #include #include #define LOG_LEVEL 2 #include LOG_MODULE_REGISTER(led); #include #define MAX_DUTY (32 * 255) #ifdef BOARD_LED_MAP const led_map ledmaps[] = { BOARD_LED_MAP }; struct pwm_chans{ u8_t chan; u8_t gpio_num; }; struct pwm_chans chan_gpio_num[] = { {0, 3}, {0, 4}, {0, 14}, {0, 36}, {0, 49},\ {1, 5}, {1, 15}, {1, 37}, {1, 50},\ {2, 6}, {2, 21}, {2, 38}, {2, 51},\ {3, 7}, {3, 17}, {3, 39}, {3, 52},\ {4, 8}, {4, 18}, {4, 40}, {4, 53},\ {5, 9}, {5, 19}, {5, 41}, {5, 54},\ {6, 10}, {6, 20}, {6, 42}, {6, 55},\ {7, 11}, {7, 21}, {7, 43}, {7, 45}, {7, 56},\ {8, 12}, {8, 22}, {8, 44}, {8, 46}, {8, 57},\ }; typedef struct { u8_t led_id; u8_t led_pin; u8_t led_pwm; u8_t active_level; u8_t state; led_pixel_value pixel_value; struct device *op_dev; }led_dot; typedef struct { u16_t led_dot_num; led_dot pixel[ARRAY_SIZE(ledmaps)]; }led_panel; static led_panel led; static u16_t get_chan(int led_index) { for(int i = 0; i < sizeof(chan_gpio_num)/sizeof(struct pwm_chans); i++) if(led_index == chan_gpio_num[i].gpio_num) return chan_gpio_num[i].chan; return -EINVAL; } static int led_display_init(struct device *dev) { int i = 0; ARG_UNUSED(dev); led.led_dot_num = ARRAY_SIZE(ledmaps); for (i = 0; i < led.led_dot_num; i ++) { led_dot *dot = &led.pixel[i]; dot->led_pin = ledmaps[i].led_pin; dot->led_id = ledmaps[i].led_id; dot->active_level = ledmaps[i].active_level; dot->led_pwm = ledmaps[i].led_pwm; if (dot->led_pwm != 0xff) { #ifdef CONFIG_PWM dot->op_dev = device_get_binding("PWM"); #endif } else { if(dot->led_pin/32 == 0) dot->op_dev = device_get_binding("GPIOA"); else if(dot->led_pin/32 == 1) dot->op_dev = device_get_binding("GPIOB"); else if(dot->led_pin/32 == 2) dot->op_dev = device_get_binding("GPIOC"); gpio_pin_configure(dot->op_dev, dot->led_pin%32, GPIO_OUTPUT_ACTIVE); } if (!dot->op_dev) { LOG_ERR("cannot found dev gpio \n"); goto err_exit; } memset(&dot->pixel_value, 0 , sizeof(dot->pixel_value)); } return 0; err_exit: return -1; } SYS_INIT(led_display_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); #endif int led_draw_pixel(int led_id, u32_t color, pwm_breath_ctrl_t *ctrl) { #ifdef BOARD_LED_MAP int i = 0; led_dot *dot = NULL; led_pixel_value pixel; int chan; memcpy(&pixel, &color, 4); for (i = 0; i < led.led_dot_num; i ++) { dot = &led.pixel[i]; if (dot->led_id == led_id) { break; } } if (!dot) { return 0; } dot->pixel_value = pixel; switch (pixel.op_code) { case LED_OP_OFF: if (dot->led_pwm) { #ifdef CONFIG_PWM chan = get_chan(dot->led_pin); if (dot->active_level) { pwm_pin_set_cycles(dot->op_dev, chan, MAX_DUTY, 0, START_VOLTAGE_HIGH); } else { pwm_pin_set_cycles(dot->op_dev, chan, MAX_DUTY, MAX_DUTY, START_VOLTAGE_HIGH); } #endif } else { gpio_pin_set(dot->op_dev, dot->led_pin, !(dot->active_level)); } break; case LED_OP_ON: if (dot->led_pwm) { #ifdef CONFIG_PWM chan = get_chan(dot->led_pin); if (dot->active_level) { pwm_pin_set_cycles(dot->op_dev, chan, MAX_DUTY, MAX_DUTY, START_VOLTAGE_HIGH); } else { pwm_pin_set_cycles(dot->op_dev, chan, MAX_DUTY, 0, START_VOLTAGE_HIGH); } #endif } else { gpio_pin_set(dot->op_dev, dot->led_pin, dot->active_level); } break; case LED_OP_BREATH: if (dot->led_pwm) { #ifdef CONFIG_PWM chan = get_chan(dot->led_pin); pwm_set_breath_mode(dot->op_dev, chan, ctrl); #endif } break; case LED_OP_BLINK: if (dot->led_pwm) { #ifdef CONFIG_PWM chan = get_chan(dot->led_pin); pwm_pin_set_cycles(dot->op_dev, chan, dot->pixel_value.period, dot->pixel_value.pulse, pixel.start_state); //pwm_pin_set_usec(dot->op_dev, dot->led_pwm, dot->pixel_value.period * 1000, dot->pixel_value.pulse * 1000, pixel.start_state); #endif } } #endif return 0; }