Skip to content

Latest commit

 

History

History
98 lines (76 loc) · 2.46 KB

UIOSAMPLE.md

File metadata and controls

98 lines (76 loc) · 2.46 KB

UIO Sample

Following is the normal c source code sample.
So if you want to use UIO from Nerves, you need to write as NIF.

see also. https://www.kernel.org/doc/html/v5.15/driver-api/uio-howto.html

#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>

/* we can check this size by `cat /sys/class/uio/uioX/maps/map0/size` */
#define SIZE 0x10000

#define AXI_GPIO_LED "/dev/uio0"
#define AXI_GPIO_SW_BTN "/dev/uio1"
#define PWM_RGB "/dev/uio4"

/* see. https://docs.xilinx.com/v/u/en-US/pg144-axi-gpio Register Space */
#define GPIO_DATA_ADDR_OFFSET 0x0000
#define GPIO_DATA2_ADDR_OFFSET 0x0008

/* see. https://github.com/Digilent/libpwm/blob/master/libpwm.h */
#define PWM_CTRL_OFFSET         0x0000
#define PWM_PERIOD_OFFSET       0x0008
#define PWM_DUTY_OFFSET         0x0040

int main() {
  int fd;
  fd = open(AXI_GPIO_LED, O_RDWR);
  if (fd < 0) {
    return -1;
  }

  void *led_addr = mmap(NULL, SIZE, PROT_WRITE, MAP_SHARED_VALIDATE, fd, 0);
  close(fd);

  if (led_addr == MAP_FAILED) {
    return -1;
  }

  fd = open(AXI_GPIO_SW_BTN, O_RDWR);
  if (fd < 0) {
    return -1;
  }

  void *sw_btn_addr = mmap(NULL, SIZE, PROT_READ, MAP_SHARED_VALIDATE, fd, 0);
  close(fd);

  if (sw_btn_addr == MAP_FAILED) {
    return -1;
  }

  fd = open(PWM_RGB, O_RDWR);
  if (fd < 0) {
    return -1;
  }

  void *pwm_addr = mmap(NULL, SIZE, PROT_WRITE, MAP_SHARED_VALIDATE, fd, 0);
  close(fd);

  if (pwm_addr == MAP_FAILED) {
    return -1;
  }

  uint32_t sw_bits = *(uint32_t *)(sw_btn_addr + GPIO_DATA_ADDR_OFFSET);
  int sw0, sw1, sw2, sw3;
  sw0 = (sw_bits & 0x01) >> 0;
  sw1 = (sw_bits & 0x02) >> 1;
  sw2 = (sw_bits & 0x04) >> 2;
  sw3 = (sw_bits & 0x08) >> 3;

  uint32_t btn_bits = *(uint32_t *)(sw_btn_addr + GPIO_DATA2_ADDR_OFFSET);
  int btn0, btn1, btn2, btn3;
  btn0 = (btn_bits & 0x01) >> 0;
  btn1 = (btn_bits & 0x02) >> 1;
  btn2 = (btn_bits & 0x04) >> 2;
  btn3 = (btn_bits & 0x08) >> 3;

  printf("sw = %d%d%d%d\n", sw3, sw2, sw1, sw0);
  printf("btn = %d%d%d%d\n", btn3, btn2, btn1, btn0);

  *(uint32_t *)(led_addr + GPIO_DATA_ADDR_OFFSET) = sw_bits | btn_bits;

  *(uint32_t *)(pwm_addr + PWM_CTRL_OFFSET)   = sw3;
  *(uint32_t *)(pwm_addr + PWM_PERIOD_OFFSET) = 10;
  *(uint32_t *)(pwm_addr + PWM_DUTY_OFFSET   + (4 * 2)) = sw2;
  *(uint32_t *)(pwm_addr + PWM_DUTY_OFFSET   + (4 * 1)) = sw1;
  *(uint32_t *)(pwm_addr + PWM_DUTY_OFFSET   + (4 * 0)) = sw0;

  munmap(sw_btn_addr, SIZE);
  munmap(led_addr, SIZE);
  return 0;
}