Forum: Mikrocontroller und Digitale Elektronik Linux Treiber Speicherzugriff


von Florian R. (fossa)


Lesenswert?

Hallo,

ich heiße Florian und bin Student. Innerhalb meines 6. Semesters habe 
ich in einer Firma ein BAC-Praktikum zu absolvieren, in dem ich eine 
BAC-Arbeit schreiben soll.

Als Aufgabenstellung wurde mir die Implementierung eines 
Linux-Gerätetreibers aufgegeben, für den BeagleBone Black(Sitara 
AM3358). Dieser soll eine SPI Schnittstelle zur Verfügung stellen, in 
der der BeagleBone als Slave arbeitet. Damit ich das bewerkstelligen 
kann, möchte ich einen Linux-Treiber schreiben. Ich beschäftige mich nun 
zum ersten mal praktisch mit Linux-Treibern, also bitte ich um 
Nachsicht... ;) Ich bin nun schon so weit, dass der Char Device Treiber 
läuft. Um nun die Register des Prozessors zu manipulieren, hätte ich nun 
mit request_mem_region() mir einen Speicher allokiert und mit ioremap() 
die Register in den virtuellen Speicher geholt. Leider funktioniert die 
Funktion ioread() nicht, obwohl ich ihr den Pointer von ioremap() 
übergebe.

ich hoffe, jemand weiß weiter...

LG - ein schönes Wochenende

Flo

von Clemens L. (c_l)


Lesenswert?

Florian R. schrieb:
> Dieser soll eine SPI Schnittstelle zur Verfügung stellen, in
> der der BeagleBone als Slave arbeitet.

https://groups.google.com/d/topic/beagleboard/0ge_TozyTIE
https://groups.google.com/d/topic/beagleboard/UC6pUfQXsWg

> ich hoffe, jemand weiß weiter...

Ohne Quellcode?

von Florian R. (fossa)


Lesenswert?

Da das mit den oben genannten Möglichkeiten nicht geht, würde ich es 
gerne mit dem Linuxkernel implementieren, der Prozessor kann als Slave 
arbeiten, jedoch muss ich dazu auf die Register des Prozessors zugreifen 
können.

Anbei der Code:
1
#include <linux/module.h>
2
#include <linux/kernel.h>
3
#include <linux/fs.h>
4
#include <linux/ioport.h>
5
#include <asm/uaccess.h>
6
#include <asm/io.h>
7
8
int init_module(void);
9
void cleanup_module(void);
10
static int SPI_open(struct inode *, struct file *);
11
static int SPI_release(struct inode *, struct file *);
12
static ssize_t SPI_read(struct file *, char *, size_t, loff_t *);
13
static ssize_t SPI_write(struct file *, const char *, size_t, loff_t *);
14
15
#define SUCCESS 0
16
#define FAIL -1
17
#define DEVICE_NAME "hello_1"   // DEV name as it appears in /proc/devices
18
#define BUF_LEN 80         //Max length of the message from the device
19
20
static int Major;        //Major number assigned to our device driver
21
static int Device_Open = 0;    //Device Open? ==> Prevent multiple access to device
22
static char msg[BUF_LEN];    //The msg the device will give when asked
23
static char *msg_Ptr;
24
25
unsigned long rev_address_start = 0x4803014C;
26
unsigned long len = 4;
27
struct resource* spi0_region = NULL;
28
void* pMcspi0 = NULL;
29
int register_value = 0;
30
31
static struct file_operations fops = {
32
  .read = SPI_read,
33
  .write = SPI_write,
34
  .open = SPI_open,
35
  .release = SPI_release
36
};
37
38
//////////////////// INIT AND EXIT MODULE ///////////////////////////////////////////
39
40
int init_module(void)
41
{
42
  Major = register_chrdev(0, DEVICE_NAME, &fops);
43
  
44
  if(Major < 0)
45
  {
46
    printk(KERN_ALERT "Registering char device failed with %d\n", Major);
47
    return FAIL;
48
  }
49
  
50
  printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major);
51
  printk(KERN_INFO "the driver, create a dev file with\n");
52
  printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major);
53
  printk(KERN_INFO "Try various minor numbers. Try to cat and echo to\n");
54
  printk(KERN_INFO "the device file.\n");
55
  printk(KERN_INFO "Remove the device file and module when done.\n");
56
  
57
  printk(KERN_INFO "Try to request_mem_region() for IO-memory!");
58
  
59
  spi0_region = request_mem_region(rev_address_start, len, DEVICE_NAME);
60
  
61
  if(spi0_region == NULL)
62
  {
63
    printk(KERN_INFO "Error in allocating memory region!!!");
64
    return FAIL;
65
  }
66
  
67
  printk(KERN_INFO "Allocating memory region (request_mem_region()) was successful!");
68
  printk(KERN_INFO "Try to ioremap() IO-memory!");
69
  
70
  printk(KERN_INFO "START: %d", (*spi0_region).start);
71
  printk(KERN_INFO "START: %d", (*spi0_region).end);
72
  printk(KERN_INFO "NAME: %s", (*spi0_region).name);
73
  //printk(KERN_INFO "NAME: %l", (*spi0_region).flags);
74
  
75
  /* pMcspi0 = ioremap(rev_address_start, len);
76
  
77
  if(pMcspi0 == NULL)
78
  {
79
    printk(KERN_INFO "Error in remapping memory !!!!!");
80
    
81
    printk(KERN_INFO "Deallocation of memory_region: release_mem_region()");
82
    release_mem_region(rev_address_start, len);
83
    
84
    return FAIL;
85
  }
86
  
87
  printk(KERN_INFO "Remapping IO-memory was successful!");
88
  
89
  printk(KERN_INFO "Try to read from IO-memory!");
90
  
91
  register_value = ioread32(pMcspi0); 
92
  
93
  printk(KERN_INFO "Tried to read from IO-memory!");
94
  
95
  printk(KERN_INFO "The requested revision address holds the value: %d", register_value);
96
    
97
   */
98
  
99
  printk(KERN_INFO "Initialization of SPI module was successful");
100
  
101
  return SUCCESS;
102
}
103
104
void cleanup_module(void)
105
{
106
  //int ret = unregister_chrdev(Major, DEVICE_NAME);
107
  //returns void !!!
108
  //if(unregister_chrdev(Major, DEVICE_NAME) < 0)
109
  //{
110
    //printk(KERN_ALERT "Error in unregister_chrdev: %d\n", ret)
111
  //}
112
  
113
  printk(KERN_INFO "Free allocated memory space"); 
114
  
115
  //free allocated memory space
116
  //iounmap(pMcspi0);
117
  release_mem_region(rev_address_start, len);
118
  
119
  unregister_chrdev(Major, DEVICE_NAME);
120
  printk(KERN_ALERT "Unregister char device completed!");
121
}
122
123
/////////////////////  FILE-OPERATIONS  ///////////////////////////////////////////
124
125
//called when a process tries to open the device file, like "cat /dev/mycharfile"
126
static int SPI_open(struct inode *inode, struct file *file)
127
{
128
  static int counter = 0;
129
  
130
  if (Device_Open)
131
  {
132
    return -EBUSY;
133
  }
134
  
135
  Device_Open++;
136
  sprintf(msg, "I already told you %d times Hello world!\n", counter++);
137
  msg_Ptr = msg;
138
  try_module_get(THIS_MODULE);
139
  
140
  return SUCCESS;
141
}
142
143
//called when a process closes the device file
144
static int SPI_release(struct inode *inode, struct file *file)
145
{
146
  Device_Open--;       //We are ready for our next caller
147
  
148
  module_put(THIS_MODULE);
149
  
150
  return 0;
151
}
152
153
//called when a process, which already opened the dev file, attemps to read from it
154
static ssize_t SPI_read(struct file *filp, char *buffer, size_t length, loff_t *offset)
155
{
156
  //filp:    see include/linux/fs.h
157
  //buffer:  buffer to fill with data
158
  //length:   length of the buffer
159
  
160
  //Number of bytes actually written to the buffer
161
  int bytes_read = 0;
162
  
163
  //if end if message => sign EOF
164
  if(*msg_Ptr == 0)
165
  {
166
    return 0;
167
  }
168
  
169
  //Put data into buffer
170
  while(length && *msg_Ptr)
171
  {
172
    //buffer is in the user data segment, not kernel,
173
    //therefore "*" wont work => we have to use put_user
174
    //put_user copies data from kernel data segment to user data segment
175
    put_user(*(msg_Ptr++), buffer++);
176
    
177
    length--;
178
    bytes_read++;
179
  }
180
  
181
  //Most read functions are returning the number of bytes put into buffer
182
  return bytes_read;
183
}
184
185
//called when a process writes to dev file: "echo "hi" > /dev/hello
186
static ssize_t SPI_write(struct file *filp, const char *buff, size_t len, loff_t *off)
187
{
188
  printk(KERN_ALERT "Sorry, this operation is not supported.\n");
189
  return -EINVAL;
190
}

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Florian R. schrieb:
> Um nun die Register des Prozessors zu manipulieren,

Was hat das mit einem SPI-Devicetreiber zu tun? Was für Daten soll der 
"Slave"-Treiber denn dem Master zur Verfügung stellen?

Das klingt reichlich wirr.

von Strubi (Gast)


Lesenswert?

Moin,

von einem solchen Vorhaben kann ich gleich abraten, ein Linux-Host kann 
niemals zuverlässig als SPI Slave arbeiten. Das hat schlicht damit zu 
tun, dass das Timing von Linux nicht garantiert werden kann. Was geht, 
ist i2c.
Tut mir leid, aber hier erschleicht sich der Eindruck, dass der 
Aufgabensteller nicht viel nachgedacht hat. Für einen SPI Slave ist auf 
jeden Fall eine HW-Implementierung nötig. Also, wenn es denn eine 
Übungsaufgabe mit Sinn sein soll: Gleich zum FPGA greifen.

Grüsse,

- Strubi

von Clemens L. (c_l)


Lesenswert?

Es wäre vielleicht eine bessere Idee, den SPI-(Master-)Treiber 
entsprechend anzupassen:
https://e2e.ti.com/support/arm/sitara_arm/f/791/p/281877/987362
https://patchwork.kernel.org/patch/76677/

von Clemens L. (c_l)


Lesenswert?

Strubi schrieb:
> ein Linux-Host kann niemals zuverlässig als SPI Slave arbeiten.

Eine allgemeine SPI-Schnittstelle, bei der man in Echtzeit reagieren 
muss, ist in der Tat nicht möglich.

Allerdings haben die McSPI FIFOs und DMA-Unterstützung; je nach Art des 
tatsächlich verwendeten Protokolls könnte man damit durchaus etwas 
anfangen.

von foobar (Gast)


Lesenswert?

Schau dir mal die PRUs auf dem BBB an.

von Hellmut K. (hkohlsdorf)


Lesenswert?

Ich kann hier nur auf die Möglichkeit verweisen mit dem reservieren 
eines der Cores für den Echtzeit betrieb. Stichwörter „Mercury” und 
„Cobalt”. So würde das Linux um den Echtzeit fähigen „Cobalt” erweitert.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.