Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
16 years ago

Accessing Hardware from user space

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 = '0' then
      timestamp_write := (others => '0');
      timestamp_read := (others => '0');
      converted := FALSE;
    elsif rising_edge(clk) then
      if write = '1' and chipselect = '1' 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 = '0' and chipselect = '1' 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 ?

4 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    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
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    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.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    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
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    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