Nios® V/II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® V/II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++
12745 Discussions

Accessing Hardware from user space

Altera_Forum
Honored Contributor II
1,418 Views

Hi all, I've trayed to make a color space converter device to integrate in NiosII project. I follow this (http://www.nioswiki.com/accessing_hardware_registers_from_user_space_programs). This is my vhdl code : 

library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_signed.all; use ieee.std_logic_unsigned.all; use ieee.math_real.all; entity csc_custom is port(   signal clk        : IN  std_logic;   signal reset_n    : IN  std_logic;   -- interface Avalon ( Segnali per SOPC Builder)   signal chipselect : IN  std_logic;   signal writedata  : IN  std_logic_vector(31 downto 0);   signal readdata   : OUT std_logic_vector(31 downto 0);   signal write      : IN  std_logic); end entity csc_custom; architecture europa of csc_custom is begin   process(clk, reset_n)   variable timestamp_write : std_logic_vector(31  downto 0);   variable timestamp_read : std_logic_vector(31  downto 0);   variable R       : integer;   variable G       : integer;   variable B       : integer;   variable Y       : integer;   variable Cr      : integer;   variable Cb      : integer;   variable tmp1    : unsigned (15 downto 0);   variable tmp2    : unsigned (15 downto 0);   variable tmp3    : unsigned (15 downto 0);   variable converted : boolean;   begin      if reset_n = &#39;0&#39; then       timestamp_write := (others => &#39;0&#39;);       timestamp_read := (others => &#39;0&#39;);       converted := FALSE;     elsif rising_edge(clk) then       if write = &#39;1&#39; and chipselect = &#39;1&#39; and converted = FALSE then         timestamp_write := writedata;             -- Qui faccio le diverse operazioni sui tre byte             R := conv_integer(unsigned(timestamp_write( 23 downto  16)));             G := conv_integer(unsigned(timestamp_write( 15 downto  8)));             B := conv_integer(unsigned(timestamp_write( 7 downto  0)));             Y := 66 * R + 129 * G + 25 * B;             Cb := -38 * R - 74 * G + 112 * B;             Cr := 112 * R - 94 * G - 18 * B;             tmp1 := conv_unsigned(Y,16) + 128;             timestamp_write( 23 downto 16) := conv_std_logic_vector(tmp1( 15 downto 8) + 16,8);             tmp2 := conv_unsigned(Cr,16) + 128;             timestamp_write( 15 downto 8) := conv_std_logic_vector(tmp2( 15 downto 8) + 128,8);             tmp3 := conv_unsigned(Cb,16) + 128;             timestamp_write( 7 downto 0) := conv_std_logic_vector(tmp3( 15 downto 8) + 128,8);             converted := TRUE;             timestamp_read := timestamp_write;       elsif write = &#39;0&#39; and chipselect = &#39;1&#39; and converted = TRUE then             readdata <= timestamp_read;             converted := FALSE;       end if;     end if;   end process; end europa; 

I&#39;ve made a functional simulation with Quartus and the code seems work (when I write in Avalon, I make the conversion and when I read in Avalon, I read the converted value). This is my modified module driver : 

#include <linux/module.h># include <linux/kernel.h># include <linux/errno.h># include <linux/mm.h># include <linux/fs.h># include <linux/cdev.h> # include <asm/io.h># include <asm/uaccess.h> # include <asm-nios2/nios2.h> # define DEBUG# undef DEBUG # define CSC_CUSTOM_BASE_ADDR            na_custom# define CSC_CUSTOM_SIZE                 4 MODULE_AUTHOR("Stefano CAMPITELLI"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Module for Color Space Converter RGB->YUV /dev/csc_custom"); MODULE_SUPPORTED_DEVICE("none"); # define CSC_CUSTOM_MAJOR                     251# define CSC_CUSTOM_MINOR                     0 static int csc_custom_open(struct inode*, struct file*); static int csc_custom_release(struct inode*, struct file*); static int csc_custom_mmap(struct file *file, struct vm_area_struct * vma); static unsigned long csc_custom_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags); static struct csc_custom_dev_t {         int __iomem*  membase;         struct cdev   cdev; } s_csc_custom_dev; /* definitions, which functions are called for /dev/csc */ static struct file_operations fops_csc_custom = {         .mmap    = csc_custom_mmap,         .open    = csc_custom_open,         .release = csc_custom_release,         .get_unmapped_area = csc_custom_get_unmapped_area, }; /* called when data device file is opened */ static int csc_custom_open(struct inode *inode, struct file *filp) {         struct csc_custom_dev_t *dev = container_of(inode->i_cdev, struct csc_custom_dev_t, cdev);         filp->private_data = dev;         return 0; } /* called when process closes data device file */ static int csc_custom_release(struct inode *inode, struct file *filp) {         return 0; } /* called when a process mmap from data file */ static int csc_custom_mmap(struct file *filp, struct vm_area_struct * vma) {         struct csc_custom_dev_t *dev = (struct csc_custom_dev_t*)filp->private_data;         vma->vm_flags |= VM_MAYSHARE | VM_SHARED;         vma->vm_start = (unsigned long)dev->membase;         vma->vm_end = vma->vm_start + CSC_CUSTOM_SIZE;         return 0; } static unsigned long csc_custom_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) {         return pgoff << PAGE_SHIFT; } static int __init mod_init(void) {         int res;         dev_t devno = MKDEV(CSC_CUSTOM_MAJOR, CSC_CUSTOM_MINOR);         struct csc_custom_dev_t *dev = &s_csc_custom_dev;         cdev_init(&dev->cdev, &fops_csc_custom);         dev->cdev.owner = THIS_MODULE;         dev->membase = ioremap(CSC_CUSTOM_BASE_ADDR, CSC_CUSTOM_SIZE);         res = register_chrdev_region(devno, 1, "csc_custom");         if (res)         {                 printk(KERN_NOTICE "Can&#39;t get major %d for CSC_CUSTOM", CSC_CUSTOM_MAJOR);                 return res;         }         res = cdev_add(&dev->cdev, devno, 1);         if (res)         {                 printk(KERN_NOTICE "Error %d adding CSC_CUSTOM", res);                 unregister_chrdev_region(devno, 1);                 return res;         }         printk(KERN_INFO "csc_custom: Color Space Converter (RGB->YUV) driver v0.0 (lug 2009) by campo85 at 0x%p\n",dev->membase);         return res; } /* exit the module */ static void __exit mod_exit(void) {         cdev_del(&s_csc_custom_dev.cdev);         unregister_chrdev_region(MKDEV(CSC_CUSTOM_MAJOR, CSC_CUSTOM_MINOR), 1); } /* what are the module init/exit functions */ module_init(mod_init); module_exit(mod_exit); 

 

and now this is my test program : 

#include <unistd.h># include <fcntl.h># include <sys/mman.h># include <asm/types.h># include <stdio.h># include <stdlib.h> static volatile unsigned long* pCsc = 0; static int CscFd = -1; /* init */ int CscInit() {         if ((CscFd = open("/dev/csc_custom", O_RDWR)) != -1) {                 pCsc = (unsigned long*)mmap(0, 4, PROT_READ | PROT_WRITE, MAP_SHARED, CscFd, 0);                 if (pCsc == MAP_FAILED) return -1;         }         return CscFd; } /* utilization */ int GetYUV() {           return *pCsc; } /* deInit */ int CscEnd() {           if (pCsc != MAP_FAILED) munmap((void*)pCsc, 4);           if (CscFd != -1) close(CscFd);           return 0; } void GiveRGB(unsigned long *pRGB) {         *pCsc = *pRGB;         return; } int main(int argc, char *argv) {         CscInit();         __u8 *R,*G,*B,*Y,*Cr,*Cb;         unsigned long *tmp = (unsigned long *) malloc( sizeof(unsigned long));         int *tripletta = (int *) malloc(sizeof(int) * 3);         *tmp = 0;         B = (__u8 *) tmp;         G = B + 1;         R = B + 2;         *R = 23;         *G = 130;         *B = 100;         tripletta = *R;         tripletta = *G;         tripletta = *B;         printf("Tripletta RGB : %d %d %d\n",tripletta,tripletta,tripletta);         GiveRGB(tmp);         *tmp =(unsigned long) GetYUV;         Cb = (__u8 *) tmp;         Cr = Cb + 1;         Y = Cb + 2;         tripletta = *Y;         tripletta = *Cr;         tripletta = *Cb;         printf("Tripletta YCrCb : %d %d %d\n",tripletta,tripletta,tripletta);         *R = 0;         *G = 0;         *B = 0;         tripletta = *R;         tripletta = *G;         tripletta = *B;         printf("Tripletta RGB : %d %d %d\n",tripletta,tripletta,tripletta);         GiveRGB(tmp);         *tmp =(unsigned long) GetYUV;         Cb = (__u8 *) tmp;         Cr = Cb + 1;         Y = Cb + 2;         tripletta = *Y;         tripletta = *Cr;         tripletta = *Cb;         printf("Tripletta YCrCb : %d %d %d\n",tripletta,tripletta,tripletta);         *R = 255;         *G = 255;         *B = 255;         tripletta = *R;         tripletta = *G;         tripletta = *B;         printf("Tripletta RGB : %d %d %d\n",tripletta,tripletta,tripletta);         GiveRGB(tmp);         *tmp =(unsigned long) GetYUV;         Cb = (__u8 *) tmp;         Cr = Cb + 1;         Y = Cb + 2;         tripletta = *Y;         tripletta = *Cr;         tripletta = *Cb;         printf("Tripletta YCrCb : %d %d %d\n",tripletta,tripletta,tripletta);         free(tripletta);         CscEnd();         return 0; } 

When I try to run the test program I always receive the same wrong output. Someone can help me ?
0 Kudos
4 Replies
Altera_Forum
Honored Contributor II
565 Views

What about debugging ? :) 

 

If you want to invite somebody to help you you should post a very short code example that does not work. 

 

-Michael
0 Kudos
Altera_Forum
Honored Contributor II
565 Views

The problem is that I don&#39;t know what&#39;s part doesn&#39;t work. I think, that VHDL code (not integrated in Nios) works. I&#39;ve made a functional simulation and it seems to be all ok (when write signal is high I convert the the RGB triple). So , maybe, is a software problem. The (test (http://pastebin.com/f3a79f68c)) was written in good part by me following this (http://www.nioswiki.com/accessing_hardware_registers_from_user_space_programs) . In your opinion where is the problem ( vhdl, module, test) ? Sorry for my horrible english and my ignorance, but I&#39;m very newbe about module programming.

0 Kudos
Altera_Forum
Honored Contributor II
565 Views

So I sugget that you first try to get going something simpler (i. e. accising a PIO bit I/O using the MMap driver). 

 

-Michael
0 Kudos
Altera_Forum
Honored Contributor II
565 Views

Hi, I&#39;ve resolved. The problem wereseveral. First one I&#39;ve made some error during the creation of the node /dev/csc_custom. Then the test cose was incomplete. Thanks to everyone for help. Finally I finish my graduation thesis :lol: . Bye

0 Kudos
Reply