mandag den 15. november 2010

Opgave 9
Assambly-koden:
#Testing r-format arithmetic operators

#init registers
.register $s0 -10
.register $s1 5
.register $s2 3


main: add $s3, $s1, $s1 #5+5
add $s4, $s1, $s0 #5+-10
sub $s5, $s1, $s2 #5-3
sub $s6, $s2, $s1 #3-5
and $s7, $s2, $s1 #011 AND 101
exit:

Hvad gør den??

Den første instruktion tager register 1 (5) og lægger sammen med register 1 (5), og putter svaret i reg 3.
Den anden instruktion tager register 1 (5) og lægger sammen med register 0 (-10), og putter svaret i reg 4.
Den tredje instruktion tager register 2 (3) og trækker fra register 1 (5), og putter svaret i reg 5.
Den fjerde instruktion tager register 1 (5) og trækker fra register 2 (3), og putter svaret i reg 6.
Den femte instruktion tager register 2 (3) og adder med register 1 (5), og putter svaret i reg 7.

Opgave 1 : Basic arithmetic
• Hvilke enheder benyttes?
Programcounter
Sender med specifikke mellemrum adressen til næste kommando.
Programinkriminator
Inkrimentere programcounterværdien
'Programinstruktionsstørrelseinkriminator
Udsender en hardcoded værdi af kommandolængden.
Instruktionshukommelsen
Udsender instruktionen tilsvarende til det som kommandoen peger på i dens hukommelse.
Splitter
Opdeler instruktionen i de forskellige registre og funktionaliteter.
Registerbank
Indlæser de to inputregistre, samt klargør outputregistret.
Registerbankkontrol
Vælger funktionalitet af registerbanken
Hovedaritmetik
Udregner arimitikopgaven på 2 input.
Hovedaritmetikkontrol
Angiver funktionalitet til hovediarimtikken ud fra instruktion.

• Hvilke afhængigheder eksisterer?
alle enheder afhænger af hinanden

• I hvilken rækkefølge udføres operationerne?
Programcounteren sætter takten for hele svineriet.
rækkefølgen for svineriet er:
der hentes en instruktion, instruktionen opdeles i registrer og funktionalitet, parallelt sendes registrende til registerbanken, samt funktionaliteten sendes til Hovedaritmetikkontrol, registerbanken modtager kontrolfunktionalitet fra registerkontrollen, parallelt klargøres outputregistret mens værdien fra de to inputregistre hentes og outputtes, hovedarimitik modtager funktionalitet fra hovedaritmitkkontrol, hovedaritmitik modtager to inputværdier, behandler aritmetisk og outputter dem, registerbanken modtager resultatet, og putter det ned i det klargjorte register.

• Svarer det overens med det forventede?

mandag den 8. november 2010

Opgave 8
I denne øvelse skal vi lave en tilføjelse til vores GPIO driver. Vha et ioctl kald skal det være muligt at sætte en output pin til at toggle med et fast interval.

Implementer ioctl kald
ved ioctl kladet udskriver vi til kernen:
IOCTL kladet implimenteres ligesom en read eller write funktion i driveren. IOTCL kan tilgås fra userspace ligesom read og write, og bruges ofte til at sætte driveren op til noget speceilt, det kunne f.eks. være baud-rate på en serial-driver.
IOCTL funktionen skal kaldes med et IOCTL-nummer. Da ioctl-numrene er globale skal man først sikre sig at man vælger et nummer der ikke er optaget. Alt under 1000 er med stor sikkerhed optaget allerede (enten af systemet eller andre drivere) så derfor valgte vi to vilkårlige tal over 1000. Valget faldt på 1101 og 1102.

Det første vi gør er at tilføje IOCTL i file_operations, så muligheden for IOCTL er der:
I vores file_operations struct tilføjer vi muligheden for ioctl-kald.

struct file_operations mygpio_Fops =
{
.owner = THIS_MODULE,
.open = mygpio_open,
.release = mygpio_release,
.write = mygpio_write,
.read = mygpio_read,
.ioctl = mygpio_ioctl,
};

Dernæst skal vi angive vores magiske IOCTL numre:
#define JOE1 1101
#define JOE2 1102

Så implimentere vi IOCTL-funktionen:
size_t mygpio_ioctl(struct inode* Inode, struct file* filep, unsigned int cmd, unsigned long arg)
{
int minor = MINOR(filep->f_dentry->d_inode->i_rdev);
switch(cmd)
{
case JOE1:
printk(KERN_ALERT "Det var en etter\n");
break;
case JOE2:
printk(KERN_ALERT "Det var en toer %i\n", arg);
break;
default:
printk(KERN_ALERT "Defualt default!\n");
break;
}
return 0;
}

Læg mærke til case: JOE2, hvor vi samtidig udskriver arg, denne angiver nemlig hvilke argumenter vi sender med.

Vi laver en applikation der kan kontrollere driveren fra userspace:

#include <linux/gpio.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/timer.h>

int main()
{

int fd = open ( "/dev/joenode1", O_RDWR | 0666);

ioctl(fd, 1101); //burde udskrive Det var en etter til kernen
close(filePtr);
int fd = open ( "/dev/joenode1", O_RDWR | 0666);

ioctl(fd, 1102, 7); //sender 7 med som argument
//burde udskrive Det var en toer 7 til kernen
close(filePtr);
return 0;
}

Test:
Først indsætter vi modulet, og opretter noden, og køre dmesg:

kører vores testprogram, og ser hvad der sker:

Implementer toggler
vi valgte kun at implimentere en timer der ikke belastede CPU'en da denne er den mest anvendelige, og vi var lidt bagefter med CPAC opgaverne..


Til timeren brugte vi siden her som inspiration:
og kom frem til følgende kode som fungerede:
size_t mygpio_ioctl(struct inode* Inode, struct file* filep, unsigned int cmd, unsigned long arg)
{
int minor = MINOR(filep->f_dentry->d_inode->i_rdev);
switch(cmd)
{
case INIT_TIMER:
printk("Init timer!\n");
init_timer(&my_timer);
//jiffies og HZ er system vaiabler der angiver tiden
my_timer.expires = jiffies + arg*HZ;
my_timer.function = timer_func;
my_timer.data = arg;
add_timer(&my_timer);
break;
case SET_INTERVAL:
printk("Setting interval %i\n", arg);
my_timer.expires = jiffies + arg*HZ;
break;
case EXIT_TIMER:
printk("Exit timer!\n");
del_timer_sync(&my_timer);
break;
default:
printk("Defualt case entered!\n");
}
return 0;
}

//og her den timer_func der udføres når den udløber
static void timer_func(long int arg)
{
printk("Entering timer_func");
//init_timer(&my_timer);
add_timer(&my_timer);
my_timer.expires = jiffies + arg*HZ;
my_timer.function = timer_func;
my_timer.data = arg;
if(val == 1)
{
printk("Setting val %i\n", val);
gpio_set_value(139, 1);
val = 0;
}
else
{
printk("Setting val %i\n", val);
gpio_set_value(139, 0);
val = 1;
}
}

VI fik LED'erne til at blinke med et interval vi sendte fra userspace med et kald til IOCTL, med numret for den anden IOCTL kommando, hvor vi kunne sætte intervallet for blinket, og den gjorde og alt var godt : ) : ) : ) : )

mandag den 11. oktober 2010

Opgave 7
- Find ud af hvordan DAC7612 er forbundet til OMAP’en
Forbundet Bus 1, chipsselect 3

- Find ud af DAC7612’s SPI karakteristika.
CPOL = 1;
CPHA = 1;

- Indsæt værdier i board struct’en, ret number of bit_per_word i spi_probe
i ads7870-core.c ændres structen således:
.bus_num = 1,
.chip_select = 3,
i ads7870-core.c ændres metoden __devinit ads7870_spi_probe
så bit_pr_word = 14;

- Indsæt nogle debug printk’er

Implementer write
Da vi skal implimentere write før vi kan sætte en default værdi, gør vi dette først. Efter vi har sat defaultværdien implementerer i wiritefunktionen (ads7870_cdrv_write i filen dac7612.c)

ssize_t ads7870_cdrv_write(struct file *filep, const char __user *ubuf,
size_t count, loff_t *f_pos)
{
int minor, len, value;
char kbuf[MAXLEN];

minor = MINOR(filep->f_dentry->d_inode->i_rdev);

len = count < (MAXLEN - 1) ? count : MAXLEN;

copy_from_user(kbuf, ubuf, len);

sscanf(kbuf, "%i", &value);

dac7612_write(minor, value);
return count;
}


Hvorefter vi kan måle på Devkittet at udgangen ændrede spænding når vi skrev til devicet.
echo 1000 >/dev/dac0
giver en spænding på 1000mV
.

mandag den 4. oktober 2010

Øvelse 6 - Interrputs

Implementer Interrupt request/free
Requester interrupt i interrupt.c (modificeret øvelse 5)
indsættes i init lige før return:

unsigned int IRQ = gpio_to_irq(130);


request_irq(IRQ, myISR, IRQF_TRIGGER_RISING, "Joe", NULL);
printk("IRQ-line: %d", IRQ);
//der ses med dmesg hvilket IRQ-linie vi får tildelt.

implimenter pseudo myISR, som kører printk(KERN_ALERT "IRQ event!!!\n");.

Implementer ISR
Der er et eksempel på wait() på side 160 i LDD3.
Tilføj følgende kode i toppen af filen, som global variabel.

static DECLARE_WAIT_QUEUE_HEAD(wq);
static int flag = 0;

I mygpio_read( ) på linie 278 og 279 tilføjes følgende kode.
flag = 0;
wait_event_interruptible(wq, flag!=0);

I mypgio_isr( ) implimenteres således:

vi forbinder interruptbenet til GROUND
indsætter modul:
insmod interrupts.ko

VI skifter benet over til VCC, og bagefter til GND igen.

vi kigger i dmesg, og ser at der sket nogle interrupts.


Øvelse 5 - GPIO Linux Device Driver

Implementer ”init” og ”exit”
/*
* ID: mygpio.c
*/
#include
#include
#include
#include
#include

#define MYGPIO_MAJOR 62
#define MYGPIO_MINOR 0
#define MYGPIO_CHS 8
#define MAXLEN 512

static struct cdev MyGpioDev;
struct file_operations mygpio_Fops;

static int devno;

const unsigned int gpio_len = 8;
struct gpioPort{
unsigned int num;
enum direnu { in, out } dir;
const char label[10]; // Very important to specify a size. Just [] causes havoc to gpio indexing
} gpio[] = {
{130, in, "gpio0_0"},
{131, in, "gpio0_1"},
{132, in, "gpio0_2"},
{133, in, "gpio0_3"},
{134, out, "gpio0_4"},
{135, out, "gpio0_5"},
{136, out, "gpio0_6"},
{137, out, "gpio0_7"},
{139, out, "gpio0_9"}
};


static int mygpio_init(void)
{
int err, i;

printk(KERN_ALERT "Mygpio Module Inserted\n");


/*
* Allocate Major/Minor Numbers
*/
devno = MKDEV(MYGPIO_MAJOR, MYGPIO_MINOR);
if((err=register_chrdev_region(devno, gpio_len, "myGpio"))<0){
printk(KERN_ALERT "Can't Register Major no: %i\n", MYGPIO_MAJOR);
return err;
}

/*
* Create cdev
*/
cdev_init(&MyGpioDev, &mygpio_Fops);
MyGpioDev.owner = THIS_MODULE;
MyGpioDev.ops = &mygpio_Fops;
err = cdev_add(&MyGpioDev, devno, gpio_len);
if (err) {
printk (KERN_ALERT "Error %d adding MyGpio device\n", err);
return -1;
}

/*
* Request GPIO Ressources
*/

/*** YOUR CODE HERE ****/

//gpio_request(139, gpio);
gpio_request(130, "GPIO0_0");

/*
* Set GPIO Direction
*/

/*** YOUR CODE HERE ****/
//gpio_direction_output(139, 1);
gpio_direction_input(130);


return 0;
}

static void mygpio_exit(void)
{
int i;

printk(KERN_NOTICE "Removing Mygpio Module\n");

/*
* Set GPIOs to Inputs
* (leave things as when we entered)
*/

/*** YOUR CODE HERE ****/
gpio_direction_input(139);


/*
* Free GPIO Ressources
*/

/*** YOUR CODE HERE ****/
//gpio_free(139);
gpio_free(130);


/*
* Delete cdev
*/
unregister_chrdev_region(devno, gpio_len);
cdev_del(&MyGpioDev);
}


Implementer ”open” og ”release”
int mygpio_open(struct inode *inode, struct file *filep)
{
int major, minor;

major = MAJOR(inode->i_rdev);
minor = MINOR(inode->i_rdev);

printk("Opening MyGpio Device [major], [minor]: %i, %i\n", major, minor);


/*
* Check if major/minor is valid
*/

/*** YOUR CODE HERE ****/


/*
* Try to get the module sem
*/
if (!try_module_get(mygpio_Fops.owner)) // Get Module
return -ENODEV;

return 0;
}

int mygpio_release(struct inode *inode, struct file *filep)
{
int minor, major;

major = MAJOR(inode->i_rdev);
minor = MINOR(inode->i_rdev);

printk("Closing MyGpio Device [major], [minor]: %i, %i\n", major, minor);


/*
* Check if major/minor is valid
*/

/*** YOUR CODE HERE ****/


/*
* Put the module semaphore
* to release it
*/
module_put(mygpio_Fops.owner);

return 0;
}


Implementer ”write”
ssize_t mygpio_write(struct file *filep, const char __user *ubuf,
size_t count, loff_t *f_pos)
{
int minor, len, value;
char kbuf[MAXLEN];

/*
* retrieve minor from file ptr
*/
minor = MINOR(filep->f_dentry->d_inode->i_rdev);
printk(KERN_ALERT "Writing to MyGpio [Minor] %i \n", minor);

/*
* Check if minor is valid
*/

/*** YOUR CODE HERE ****/

/*
* Copy data from user space
* to kernel space
*/
len = count < MAXLEN ? count : MAXLEN; // set len < MAXLEN

/**** Use copy_from_user to get data ****/
/*** YOUR CODE HERE ****/
copy_from_user(kbuf, ubuf, count);

kbuf[len] = '\0'; // Pad null termination to string
printk("string from user: %s\n", kbuf);

/*
* Convert string to int
*/

/**** Use sscanf to convert string to int ****/
/*** YOUR CODE HERE ****/
sscanf(kbuf,"%i", &value);
printk("value %i\n", value);

value = value > 0 ? 1 : 0;

/*
* Set GPIO port
* (if an output port)
*/

/**** Use gpio_set_value on appropriate port ****/
/*** YOUR CODE HERE ****/
gpio_set_value(139, value);

*f_pos += count;
return count;
}

Implementer ”read”
ssize_t mygpio_read(struct file *filep, char __user *buf,
size_t count, loff_t *f_pos)
{
char readBuf[MAXLEN];
int len, result=-1, minor;

/*
* retrieve minor from file ptr
*/
minor = MINOR(filep->f_dentry->d_inode->i_rdev);
printk(KERN_ALERT "Reading from MyGpio [Minor] %i \n", minor);

/*
* Check if minor is valid
*/

/*** YOUR CODE HERE ****/

/*
* Read GPIO port
* (if an input port)
*/

/*** YOUR CODE HERE ****/
result = gpio_get_value(130);

/*
* Convert int to string
* using sprintf
*/
len=sprintf(readBuf,"%i", result);
len++; // To include null-termination

/*
* Copy string result
* to User Space
*/

/*** YOUR CODE HERE ****/
copy_to_user(buf, readBuf, len);

*f_pos += len;
return len;
}


struct file_operations mygpio_Fops =
{
.owner = THIS_MODULE,
.open = mygpio_open,
.release = mygpio_release,
.write = mygpio_write,
.read = mygpio_read,
};

module_init(mygpio_init);
module_exit(mygpio_exit);

MODULE_DESCRIPTION("My GPIO Module");
MODULE_AUTHOR("IHA ");
MODULE_LICENSE("GPL");


Indsæt modul, node, kørsel af læsningsprogram
insmod mygpio.ko
mknod /dev/wepee c 62
./rd /dev/wepee

mandag den 20. september 2010

Øvelse 4 - konstruer et kerne modul

optakt

konstruer "Hello World" modul til kernen.
Vi kopierer hello world programmet fra bogen.
Vi kopierede make filen fra bogen
vi tilrettede stien hvormed den konstruerede indstillingerne af hvilket Target vi har
vi kører makefilen
en hello.ko fil er nu konstrueret
med scp kopierer vi hello.ko over på target
på target loader vi hello.ko ind i kernen med komandoen: insmod hello.ko
vi ser på mod listen at modulet er tilgængeligt med komandoen: lsmod
vi kan se at der er en "hello" tilgængelig
med kommandoen dmesg kan vi se hvile outputs de forskellige kerne moduler afgiver
vi kan se at "hello world" står sidst på listen
vi sletter modulet med kommandoen: rmmod hello
vi kigger i mod listen med komandoen: lsmod
vi kan du se sidst på listen at hello er blevet nedlagt da der er udskrevet "goodby crule world"

Opgave 1.

Vi overskrev det oprindelige uImage, med vores eget fra tidligere opgave, der indeholdte LED-driver.
vi skrev et .c program der hvert sekund skrev skifte vis 0 eller 1 til filen brigthness, under vores egen diode, og derved ændrede LED'ens tilstand.

mandag den 13. september 2010

Øvelse 3 - bygning af Linux kernen

Vi har været i gang med at boot'e DK8000 men vores egen udgave af styresystemet.
Vi har ændret i værdierne for nogel GPIO så de passer med en diode der sidder på addon boaded. på forbindelse 139 sidder der LED3. Vi har tilføjet dioden så denhedder "YAHOO".

efter at have tilføjet det nye hardware kompilerede vi med:

make uImage

efter dette kopierer vi vores eget kompilerede image over på SD kortet og kalder det My_uImage for ikke at overksrive det oprindelige image

Vi sætter kortet i og tænder for DK8000

Vi afbryder defauld boot'en på DK8000.

Vi initierer hukommelsen:

mmcinit

Vi indlæser vores eget boot image på adressen 0x80300000

fatload mmc 0 0x80300000 My_uImage

vores image er nu indlæst på adressen

vi boot'er fra den adresse:

bootm 0x80300000

Ved boot lyser lysdioden