Główna

Programowanie


Siłą rzeczy i zainteresowań zajmuję się programowaniem w Assemblerze i embedded C. Kiedy pojawia się potrzeba zajmuję się również programowaniem wyższych warstw w C oraz C++ obiektowo.
Mam również doświadczenie w pisaniu prostych aplikacji pod system Android. W tym dziale będę zamieszczał kody źródłowe poszczególnych projektów oraz okazyjnie kody nie związane z programowaniem kontrolerów lecz z typowo programistycznymi zadaniami.

Poniżej prezentuję fragment kodu sterownika kernela dla portów GPIO oraz aplikację korzystającą ze sterownika.

  • Definiowanie zasobów sterownika
  • Kod sterownika GPIO dedykowanego MCU STM32
  • Kod aplikacji operującej na portach I/O

Definiowanie zasobów sterownika
(widok pełnoekranowy)

static struct resource stm3210e_eval_gpios_resources[] = { [0] = { .start = 0, .end = 15, .flags = IORESOURCE_IRQ, }, [1] = { .start = 0, .end = 15, .flags = IORESOURCE_IRQ, }, }; static struct platform_device stm3210e_eval_gpios_device = { .name = "io-gpio", .id = -1, .num_resources = 2, .resource = stm3210e_eval_gpios_resources, };

Sterownik GPIO kernela dla STM32
(widok pełnoekranowy)

/* * Character driver for ARM STM32 chip GPIO port implemented * separately for inputs and outputs * * Copyright © 2013 Lukasz Kazmierczak */ #include ... #define DRIVER_NAME "io-gpio" #define PFX DRIVER_NAME ": " #define DRIVER_DEVICES_NB 2U #define MAX_GPIO_RANGE 16U static int initialize_gpio_inputs(void); static int initialize_gpio_outputs(void); struct gpio_data { atomic_t open_count; }; struct group_data { dev_t dev_node; struct cdev cdev; struct resource *gpio_range; struct gpio_data *gpios; }; typedef struct group_data group_data_struct; group_data_struct *group_data_vect[DRIVER_DEVICES_NB] = {0}; int initialize_gpio_inputs() { int i=0, ret=-1; for(i=0; i < MAX_GPIO_RANGE; i++) gpio_direction_input(i, 1); if(i == MAX_GPIO_RANGE) ret = 0; return ret; } int initialize_gpio_outputs() { int i=0, ret = -1; for(i=0; i < MAX_GPIO_RANGE; i++) { gpio_direction_output(i, 0); gpio_set_value(i, 0); } if(i == MAX_GPIO_RANGE) ret = 0; return ret; } /** * simple_gpio_read - readout pin status from input port * ex. $ cat /dev/gpioG8 */ static ssize_t simple_gpioin_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { unsigned int gpio = iminor(file->f_path.dentry->d_inode); static char *buf_signature = 0; ssize_t ret = 0; //printk("gpio read requested from input port: count %d, buf %p\n", count, buf); if(count > 1 && buf_signature == buf) { //second call for exceeding data readout, abort reading buf_signature = 0; count = 0; } else if(count > 1) { //first call for exceeding data readout, return available reading buf_signature = buf; count = 3; } else { //no action defined } char byte = '0'; gpio_direction_input(gpio, 1); byte += gpio_get_value(gpio); //printk("Input readout for pin: %d is %c\n", gpio, byte); ret = count; if(count > 2) { if (put_user(byte, buf) || put_user('\n', buf + 1) || put_user('\0', buf + 2)) ret = -1; } else if(count == 1){ if (put_user(byte, buf)) ret = -1; } else { //no action defined } return ret; } /** * simple_gpio_read - readout pin status from output port: no action * ex. $ cat /dev/gpioF8 */ static ssize_t simple_gpio_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { ssize_t ret = -1; printk("gpio read requested for output port: operation not supported\n"); return ret; } /** * simple_gpioin_write - set pin state of input port to desired value: no action * ex. $ echo '1' > /dev/gpioG8 */ static ssize_t simple_gpioin_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { ssize_t ret = -1; printk("write requested for input port: operation not supported!\n"); return ret; } /** * simple_gpio_write - set pin state of output port to desired value * ex. $ echo '1' > /dev/gpioF8 */ static ssize_t simple_gpio_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { unsigned int gpio = iminor(file->f_path.dentry->d_inode); ssize_t i = 0, ret = -1; char uvalue = 0; int value = 0; //printk("gpio write requested for output port: count %d, buf %p\n", count, buf); i = 0; while (i < count) { char byte = 0; int user_ret = get_user(byte, buf + i); i++; if (user_ret) return user_ret; switch (byte) { case '\r': case '\n': continue; case 'T': case '0': case '1': uvalue = byte; break; default: uvalue = 0; i = count; } GPIO_DBG("processed byte '%c'", byte); } if(uvalue != 0) { switch (uvalue) { case 'T': value = !gpio_get_output_value(gpio); break; default: value = uvalue - '0'; } gpio_direction_output(gpio, 0); gpio_set_value(gpio, value); ret = count; } return ret; } /** * simple_gpio_open - allocate specific pin of GPIO port to be accessed * */ static int simple_gpio_open(struct inode *ino, struct file *file) { struct group_data *group_data = container_of(ino->i_cdev, struct group_data, cdev); unsigned int gpio = iminor(ino); struct gpio_data *gpio_data = &group_data->gpios[gpio - group_data->gpio_range->start]; int ret; if (gpio < group_data->gpio_range->start || gpio > group_data->gpio_range->end) return -ENXIO; ret = gpio_request(gpio, DRIVER_NAME); if (ret) return ret; atomic_inc(&gpio_data->open_count); return 0; } /** * simple_gpio_close - deallocate specific pin of GPIO port from being accessed * */ static int simple_gpio_release(struct inode *ino, struct file *file) { struct group_data *group_data = container_of(ino->i_cdev, struct group_data, cdev); unsigned int gpio = iminor(ino); struct gpio_data *gpio_data = &group_data->gpios[gpio - group_data->gpio_range->start]; /* do not free until last consumer has closed */ if (atomic_dec_and_test(&gpio_data->open_count)) gpio_free(gpio); else GPIO_DBG("gpio still in use -- not freeing"); return 0; } static int simple_gpio_ioctl(struct inode * ino, struct file * file, unsigned int a, unsigned long b) { return 0; } static struct class *simple_gpio_class; /** * simple_gpio_fops - define operations for specific resource * */ static struct file_operations simple_gpio_fops[] = { [0] = { .owner = THIS_MODULE, .read = simple_gpio_read, .write = simple_gpio_write, .open = simple_gpio_open, .release = simple_gpio_release, .ioctl = simple_gpio_ioctl, }, [1] = { .owner = THIS_MODULE, .read = simple_gpioin_read, .write = simple_gpioin_write, .open = simple_gpio_open, .release = simple_gpio_release, .ioctl = simple_gpio_ioctl, }, }; /** * simple_gpio_probe - allocate resources and bind as character devices * */ static int __devinit simple_gpio_probe(struct platform_device *pdev) { int ret = 0, dev = 0; char *devName[][DRIVER_DEVICES_NB] = { { "gpio", "gpio%i" }, { "gpioin", "gpioin%i" }, }; group_data_struct *(*group_data_init)[DRIVER_DEVICES_NB] = kzalloc(sizeof(group_data_vect), GFP_KERNEL); platform_set_drvdata(pdev, group_data_init); while(dev < DRIVER_DEVICES_NB) { struct group_data *group_data; struct resource *gpio_range = platform_get_resource(pdev, IORESOURCE_IRQ, dev); int gpio, gpio_max = gpio_range->end - gpio_range->start + 1; group_data = kzalloc(sizeof(*group_data) + sizeof(struct gpio_data) * gpio_max, GFP_KERNEL); if (!group_data) return -ENOMEM; group_data->gpio_range = gpio_range; group_data->gpios = (void *)group_data + sizeof(*group_data); (*group_data_init)[dev] = group_data; ret = alloc_chrdev_region(&group_data->dev_node, gpio_range->start, gpio_max, devName[dev][0]); if (ret) { pr_devinit(KERN_ERR PFX "unable to get a char device\n"); kfree(group_data); return ret; } cdev_init(&group_data->cdev, &simple_gpio_fops[dev]); group_data->cdev.owner = THIS_MODULE; ret = cdev_add(&group_data->cdev, group_data->dev_node, gpio_max); if (ret) { pr_devinit(KERN_ERR PFX "unable to register char device\n"); unregister_chrdev_region(group_data->dev_node, gpio_max); kfree(group_data); return ret; } for (gpio = gpio_range->start; gpio <= gpio_range->end; ++gpio) { device_create(simple_gpio_class, &pdev->dev, group_data->dev_node + gpio, NULL, devName[dev][1], (int)gpio); } device_init_wakeup(&pdev->dev, 1); pr_devinit(KERN_INFO PFX "Dev %d: now handling %i GPIOs: %i - %i, registered as %d\n", dev+1, gpio_max, gpio_range->start, gpio_range->end, MAJOR(group_data->dev_node) ); dev++; } if(ret == 0) { //no error occured, no further action needed } else if(dev > 0) { //ToDo //initisalization of second resource failed //uninitialization has to be done for the first resource } else { //ToDo //first resorce initialization failed and is uninitialized //second resource is not to be initialized } return ret; } /** * simple_gpio_remove - remove character devices of GPIO resources. */ static int __devexit simple_gpio_remove(struct platform_device *pdev) { int ret = 0, dev = 0; group_data_struct *(*group_data_deinit)[DRIVER_DEVICES_NB]=platform_get_drvdata(pdev); while(dev < DRIVER_DEVICES_NB) { struct group_data *group_data = (*group_data_deinit)[dev]; struct resource *gpio_range = group_data->gpio_range; int gpio=0, gpio_max=gpio_range->end - gpio_range->start + 1; for (gpio = gpio_range->start; gpio <= gpio_range->end; ++gpio) device_destroy(simple_gpio_class, group_data->dev_node + gpio); cdev_del(&group_data->cdev); unregister_chrdev_region(group_data->dev_node, gpio_max); kfree(group_data); dev++; } kfree(group_data_deinit); return ret; } struct platform_driver simple_gpio_device_driver = { .probe = simple_gpio_probe, .remove = __devexit_p(simple_gpio_remove), .driver = { .name = DRIVER_NAME, } }; /** * simple_gpio_init - initial startup of GPIO driver * */ static int __init simple_gpio_init(void) { //initialize_gpio_inputs(); //initialize_gpio_outputs(); simple_gpio_class = class_create(THIS_MODULE, DRIVER_NAME); if (IS_ERR(simple_gpio_class)) { pr_init(KERN_ERR PFX "unable to create gpio class\n"); return PTR_ERR(simple_gpio_class); } return platform_driver_register(&simple_gpio_device_driver); } module_init(simple_gpio_init); /** * simple_gpio_exit - dropping GPIO device driver */ static void __exit simple_gpio_exit(void) { class_destroy(simple_gpio_class); platform_driver_unregister(&simple_gpio_device_driver); } module_exit(simple_gpio_exit); MODULE_AUTHOR("Lukasz Kazmierczak"); MODULE_DESCRIPTION("STM32 input/output port driver"); MODULE_LICENSE("GPL");

Aplikacja operująca na portach I/O
(widok pełnoekranowy)

/******************************************************************************* * keyboard-LED control application * Copyright © 2013 Lukasz Kazmierczak *******************************************************************************/ #include ... #define KBD_BUTTONS 5U #define LEDS 4U #define LED_UP 1U #define LED_DOWN 2U #define LED_LEFT 0U #define LED_RIGHT 3U #define KBD_SEL 0U #define KBD_UP 2U #define KBD_DOWN 1U #define KBD_LEFT 3U #define KBD_RIGHT 4U unsigned char _term=0; static void signal_handler(int signal) { if(signal == SIGTERM) { printf("Termination signal received\n"); _term = 1; } else { // unsupported signal } } int main(int argc, char ** argv) { int LED[LEDS]={0}, KBD[KBD_BUTTONS]={0}; int ret = -1, i = 0; int kbdChkMsDelay = 100; struct timespec req = { .tv_sec=0, .tv_nsec= kbdChkMsDelay * 1000000 }; char *LED_gpio[] = { "/dev/gpioF6", "/dev/gpioF7", "/dev/gpioF8", "/dev/gpioF9" }; char *KBD_gpio[] = { "/dev/gpioG7", "/dev/gpioG8", "/dev/gpioG11", "/dev/gpioG13", "/dev/gpioG14" }; if(argc != 1) { printf("%s.\n"\ "\tapplication sets LEDs depend of JOY buttons state\n"\ "\tsignal (\"kill -TERM \") kills the application\n", argv[0]); ret = 0; } else { signal(SIGTERM, signal_handler); for(i = 0; i < LEDS; i++) LED[i] = open(LED_gpio[i], O_WRONLY); for(i = 0; i < KBD_BUTTONS; i++) KBD[i] = open(KBD_gpio[i], O_RDONLY); if(LED[0]<0||LED[1]<0||LED[2]<0||LED[3]<0) { printf("can not open gpio port for writing.\n"); return ret; } if(KBD[0]<0||KBD[1]<0||KBD[2]<0||KBD[3]<0||KBD[4]<0) { printf("can not open gpio port for reading.\n"); return ret; } for(i = 0; i < LEDS; i++) write(LED[i], "0", 1); while(_term == 0) { for (i=0; i< KBD_BUTTONS; i++) { char buttonState = 0; read(KBD[i], &buttonState, 1); buttonState = '0' + (!(buttonState - '0')); // mapping buttons to LEDs switch(i) { case KBD_UP: write(LED[LED_UP], &buttonState, 1); break; case KBD_DOWN: write(LED[LED_DOWN], &buttonState, 1); break; case KBD_LEFT: write(LED[LED_LEFT], &buttonState, 1); break; case KBD_RIGHT: write(LED[LED_RIGHT], &buttonState, 1); break; case KBD_SEL: write(LED[LED_UP], &buttonState, 1); write(LED[LED_DOWN], &buttonState, 1); write(LED[LED_LEFT], &buttonState, 1); write(LED[LED_RIGHT], &buttonState, 1); break; default: { /* button not supported */ } } } nanosleep(&req, NULL); } for(i = 0; i < LEDS; i++) write(LED[i], "0", 1); for(i = 0; i < LEDS; i++) close(LED[i]); for(i = 0; i < KBD_BUTTONS; i++) close(KBD[i]); ret = 0; } return ret; }



Do góry