LinuxQuestions.org
Help answer threads with 0 replies.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 09-29-2019, 05:47 PM   #1
Katemonster
LQ Newbie
 
Registered: Aug 2019
Posts: 12

Rep: Reputation: Disabled
Issues with SPI kernel driver for PSX controllers


Hi all.

I'm writing a module for talking to PSX/PS2 controllers. The code is here: https://github.com/katemonster33/psxpad_spi_ex

The way I'm intending it to work is, approximately every 16 ms it should do this:

1. Pull chip enable 0 low
2. Wait 100 us
3. Send a byte to SPI
4. Wait for an "acknowledge" GPIO to go low
5. Wait ~6 us
6. Repeat 3 and 4 for the remaining controller data
7. Repeat 1-6 for controller 2(chip enable 1)

To this end I've implemented a timer. During every tick it performs the steps above. However I get lots of kernel errors, it constantly says "BUG: scheduling while atomic". The stack trace shows the function where I attempt to transmit the SPI bytes.

So I didnt completely write this from scratch, I used the code from here as a base: http://domisan.sakura.ne.jp/article/psxpad/psxpad.html

His code is a bit different, he uses a polled input device, which must work better for SPI. I didnt think I could use that though, I'm intending my driver to dynamically register and unregister input devices as controllers are plugged in and unplugged. Plus, I am implementing multitap support so there could be up to 8 controllers.

Does anyone have ideas for a better method of implementing the periodic SPI transfers I need? The time between polls can vary, 10 to 25 ms is probably fine, as long as there is no noticeable delay. However, within the SPI transfer code the timing has to be extremely precise. For instance, the "acknowledge" pin only goes low for 1-2 ms, if I miss that window the driver stops working. Any wisdom would be greatly appreciated!
 
Old 09-30-2019, 08:54 AM   #2
smallpond
Senior Member
 
Registered: Feb 2011
Location: Massachusetts, USA
Distribution: CentOS 6 & 7
Posts: 3,209

Rep: Reputation: 871Reputation: 871Reputation: 871Reputation: 871Reputation: 871Reputation: 871Reputation: 871
3 of your steps say "wait". Linux kernel drivers should never wait or sleep, especially in interrupt or callback context. Run everything event-driven from the timer and completion interrupts. Keep your current state in a variable so you know when you are on step 1,2,3 etc of your list above. Use locks to protect volatile data. Have fun!
 
1 members found this post helpful.
Old 09-30-2019, 09:48 AM   #3
Katemonster
LQ Newbie
 
Registered: Aug 2019
Posts: 12

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by smallpond View Post
3 of your steps say "wait". Linux kernel drivers should never wait or sleep, especially in interrupt or callback context. Run everything event-driven from the timer and completion interrupts. Keep your current state in a variable so you know when you are on step 1,2,3 etc of your list above. Use locks to protect volatile data. Have fun!
So is it the SPI writing inside the timer that causes an issue, or the sleeping? Either way, I guess I need some more specifics. I don't really know what I'm doing, this is the first real driver I've written. I understand what you mean, kind of make a "state machine" using the timer so I'm not taking up too much CPU time. The question I have there is, can I ensure the timer will fire its interrupt within probably +/- 10% of the timing I request?

Secondly, one of the sleeps involves a loop like this:

Code:
while(waited_time < 50 us)
{
    udelay(1);
    if(ack_pin_is_low()) return 1;
}
I'm sure this is the exact kind of wait behavior you're talking about, but how do I accomplish this behavior with interrupts?

Also, assuming the SPI causes the issue, is there some callback I can setup so that the SPI comes and fetches me when the transfer is completed?
 
Old 10-03-2019, 08:51 AM   #4
Katemonster
LQ Newbie
 
Registered: Aug 2019
Posts: 12

Original Poster
Rep: Reputation: Disabled
OK, wait. I was reading about converting jiffies to microseconds. The stackoverflow page I pulled up said that anything below 1 ms likely wouldn't be accurate. So basically my calls to mod_timer can't ask to sleep for delays of 10-100 us? That's precisely what I need to make the driver work. How do I setup my state machine and timer to come get me in X number of microseconds?
 
Old 10-04-2019, 10:48 AM   #5
smallpond
Senior Member
 
Registered: Feb 2011
Location: Massachusetts, USA
Distribution: CentOS 6 & 7
Posts: 3,209

Rep: Reputation: 871Reputation: 871Reputation: 871Reputation: 871Reputation: 871Reputation: 871Reputation: 871
I'm used to Intel CPUs with high-precision timers. I'm not sure what's available on your RPi. If this is the only thing running, and you need to do some delays, you can make them as accurate as you want by temporarily disabling other interrupts. But you need to give the rest of the kernel time to run or it will get mad.
 
Old 10-06-2019, 11:51 PM   #6
Katemonster
LQ Newbie
 
Registered: Aug 2019
Posts: 12

Original Poster
Rep: Reputation: Disabled
well I found a sort of middle ground. I deleted the usage of the timer and instead am relying on a thread created using kthread_create. There's delays everywhere but there's just too many cases where it seems like there's no other way to implement it. The biggest one being that first 100 us wait after setting the chip select pin low. Unless someone can point me to a document that details some API I can use that can make some of this easier I'm not going to rewrite my whole driver using the state machine approach. I poured over everything I could find for the SPI framework in Linux and didn't find anything of use to me, in regards to microsecond-accurate delays between SPI transfers. When using the SPI from userspace, the "delay_usecs" fields of the spi_transfer struct were hilariously inaccurate.

edit: code is up-to-date on github.
 
Old 10-10-2019, 09:56 AM   #7
Katemonster
LQ Newbie
 
Registered: Aug 2019
Posts: 12

Original Poster
Rep: Reputation: Disabled
So with the new thread, I no longer see the stack traces in dmesg. However, if I rmmod the module, the created input devices stay. What do I need to call to get them to go away? input_unregister_device or whatever doesn't seem to work, they stick around like zombies.
 
Old 10-10-2019, 11:02 PM   #8
Katemonster
LQ Newbie
 
Registered: Aug 2019
Posts: 12

Original Poster
Rep: Reputation: Disabled
OK well this thread hasn't been much help but I did get it working. I can plug in a PSX multitap with 2 controllers and both can be queried reliably with jstest. Rumble works in theory but I need a 9v supply to power the motors.
 
Old 10-11-2019, 12:08 PM   #9
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=14, FreeBSD_12{.0|.1}
Posts: 5,221
Blog Entries: 11

Rep: Reputation: 3171Reputation: 3171Reputation: 3171Reputation: 3171Reputation: 3171Reputation: 3171Reputation: 3171Reputation: 3171Reputation: 3171Reputation: 3171Reputation: 3171
Quote:
Originally Posted by Katemonster View Post
OK well this thread hasn't been much help but I did get it working. I can plug in a PSX multitap with 2 controllers and both can be queried reliably with jstest. Rumble works in theory but I need a 9v supply to power the motors.
Well, that happens, but glad you got it working!

And thanks for posting your journey of discovery for others to follow!

When you are ready, please use the Thread Tools at top of the thread to mark this SOLVED.

Best of luck!
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
linux-kernel/driver/spi - General question Disciple1102 Linux - General 0 07-18-2012 04:16 PM
[SOLVED] USB PSX joystick adaptor and kernel modifications r.russo Linux - Hardware 1 06-25-2012 08:48 AM
getting kernel OOPS in SPI driver rbhsrh Linux - Kernel 2 05-09-2012 11:51 PM
Can i register a ssc driver (a serial interface device) to be a spi driver ? 5883 Programming 0 03-04-2012 06:14 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 10:50 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration