I3CPAC+Exercise+7

=Øvelse 7=

Find ud af hvordan DAC7612 er forbundet til OMAP’en
Er fundet i databladet : DAC7612 er forbundet via SPI1_SIMO_CMOS, SPI1_CLK_CMOS og SPI1_CS3_CMOS.

Find ud af DAC7612’s SPI karakteristika
Udfra timing diagrammet i databladet kan det aflæses at mode er 3 og at den benytter 14 bits per word (12 databits og 2 addresse bits, aflæst på timing diagrammet). Det kan derudover bemærkes at den kan køre med en hastighed på op til 20 MHz. Vi vælger dog en belastning på 75%, altså 15 MHz.

Indsæt værdier i board struct’en, samt ret evt number of bit_per_word i spi_probe metoden
Værdierne i structen ændres.

code format="c" struct spi_board_info omap3devkit8000_spi_board_info[] = { {   .modalias           = "dac7612", .bus_num           = 1, .chip_select       = 3, .max_speed_hz      = 15000000, .controller_data   = &dac7612_mcspi_config, .mode              = SPI_MODE_3, }, }; code

bits per word sættes i spi_probe metoden. code format="c" // ... spi->bits_per_word = 14; // ... code

Implementering af Init
Nedenfor ses produktet af en heftig omgang search & replace. Dette er koden som den ser ud efter write-blev implementeret, hvilket betyder at der altså ikke er sat en default-værdi. Hverken til init, eller exit. De linjers koder der satte en default værdi er altså fjernet i nedenstående kodesnas.

dac7612
Initfunktionen herunder står primært for at registrere devicen og kalder til sidst init funktionen i det underliggende lag. code format="c" static int __init dac7612_cdrv_init(void) { int err;

printk(KERN_ALERT "dac7612 driver initializing\n");

/* Register Char Device */ cdev_init(&dac7612Dev, &dac7612_Fops);

dac7612Dev.owner = THIS_MODULE; dac7612Dev.ops  = &dac7612_Fops;

devno          = MKDEV(DAC7612_MAJOR, DAC7612_MINOR);

err = register_chrdev_region(devno, NBR_DAC_CH, "DAConverter"); err = cdev_add(&dac7612Dev, devno, NBR_DAC_CH);

if (err) { printk (KERN_ALERT "Error %d adding DAC7612 device\n", err); return err; }

err = dac7612_init;

return err; } code

**dac7612-core**
Her konfigureres devicen vha. to structs som bruges til kaldet af initfunktionen i det nederste lag. code format="c" int dac7612_init(void) { int err;

if((err=dac7612_spi_init(&dac7612_spi_device,              &omap3devkit8000_spi_board_info[0])) < 0) printk(KERN_ALERT "init error = %i\n", err);

return err; } code

dac7612-spi
Her konfigureres bus-interfacet til enheden. code format="c" int dac7612_spi_init(struct spi_device **dac7612_spi_device,            struct spi_board_info *dac7612_spi_board_info) { int err, bus_num; struct spi_master *dac7612_spi_master;

bus_num = dac7612_spi_board_info->bus_num; dac7612_spi_master = spi_busnum_to_master(bus_num); *dac7612_spi_device = spi_new_device(dac7612_spi_master,                     dac7612_spi_board_info);

if((err=spi_register_driver(&dac7612_spi_driver))<0) printk (KERN_ALERT "Error %d registering the dac7612 SPI driver\n", err);

return err; } code

dac7612
Write funktionen i dette lag kopierer data fra user space til kernel space, og sscanf benyttes til at konvertere tekst inputtet til en integer. Denne integer bruges så i funktionskaldet til det underliggende lag. Minor nummeret aflæses ligeledes, og sendes også med. code format="c" ssize_t dac7612_cdrv_write(struct file *filep, const char __user *ubuf, size_t count, loff_t *f_pos) { int err, value; u8 minor; char kbuf[MAXLEN];

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

err = copy_from_user(kbuf, ubuf, count); if (err < 0) { printk(KERN_ALERT "Copy From User Error : %i", err); }

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

dac7612_write((u16)value, minor)

return count; } code

dac7612-core
Her sendes data og minor nummeret videre til SPI laget. code format="c" int dac7612_write(u16 value, u8 minor) {  int err = 0; err = dac7612_spi_write_reg8(dac7612_spi_device, value, minor); if (err < 0) {     printk(KERN_ALERT "Core-Write Error : %i", err); }  return err; } code

dac7612-spi
Her sammensættes beskeden som skal sendes til DAC-enheden, som herefter sendes vha. spi_sync med en spi_message og spi_transfer struct. Hvis value overstiger max værdien, bruges max værdien i stedet. code format="c" int dac7612_spi_write_reg8(struct spi_device *spi, u16 val, u8 minor) { u16 data = 0 int err = 0;

struct spi_transfer t; struct spi_message m;

memset(&t, 0, sizeof(t));

if ( val > 0x0fff ) val = 0x0fff;

/* Now we prepare the command for transferring */ data = ((1 << 13) | (1 << 12) | (val & 0x0fff));

spi_message_init(&m); m.spi = spi;

t.tx_buf = &data; t.rx_buf = NULL; t.len = 2; spi_message_add_tail(&t, &m);

err = spi_sync(m.spi, &m);

if ( err < 0 ) printk(KERN_ALERT "SPI-Write Error : %i", err);

return err;

code

Driveren er testet ved at indsætte modulet i kernen, hvor efter en node oprettes. For at sætte en værdi, echoes der til filen, og outputtet kontrolleres vha. af et multimeter. Der forventedes at outputtet giver et antal mV svarende til tallet som skrives til filen, (ex. 1.0 V målt når der echoes 1000 til filen), og vores observationer svarer overens med dette.