The spidev_test.c program from the Exploring BeagleBone by Derek Molloy (chp08) tests the SPI port by setting the SPI parameters and then writing out a test block. The text diagnostics I've added show what the macro was that is sent as part of the ioctl call. Trying to break down the macro through multiple files turned into a dead end and I'm not exactly sure what the 32 bit word means other than byte count and I believe message type.
The program starts out by sending 6 ioctl messages that configure mode, size and speed.
Here's the call that returns the 0x4006B00 and below the result of the message.
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
debian@ebb:~/exploringBB/chp08/spi/spidev_test$ ./spidev_test
SPI_IOC_WR_MODE = 40016B01
SPI_IOC_RD_MODE = 80016B01
SPI_IOC_WR_BITS_PER_WORD = 40016B03
SPI_IOC_RD_BITS_PER_WORD = 80016B03
SPI_IOC_WR_MAX_SPEED_HZ = 40046B04
SPI_IOC_RD_MAX_SPEED_HZ = 80046B04
spi mode: 0
bits per word: 8
max speed: 500000 Hz (500 KHz)
SPI_IOC_MESSAGE(1) = 40206B00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00
Now. Switch over to a part of the DisplaySPI program in the Lazarus Free Pascal pxl library the function call looks the same as do the SPI initialization calls to fpioctl. They are in a different order from the C program.
Res := fpioctl(FHandle, SPI_IOC_MESSAGE(1), @Data);
Six of the ioctl function calls do not return an error. The main one to send data has the correct
SPI_IOC_MESSAGE(1) value yet it fails.
debian@ebb:~/lazarus/pxl/Samples/FreePascal/SingleBoard/Generic/DisplaySPI$ ./DisplaySPI
UpdateFrequency -- SPI_IOC_WR_MAX_SPEED_HZ is 40046B04
UpdateFrequency -- SPI_IOC_RD_MAX_SPEED_HZ is 80046B04
UpdateBitsPerWord -- SPI_IOC_WR_BITS_PER_WORD is 40016B03
UpdateBitsPerWord -- SPI_IOC_RD_BITS_PER_WORD is 80016B03
UpdateRWMode -- SPI_IOC_WR_MODE is 40016B01
UpdateRWMode -- SPI_IOC_RD_MODE is 80016B01
SPI_IOC_MESSAGE(1) is 40206B00
An unhandled exception occurred at $000330A8:
ESysfsSPITransfer: Cannot transfer <1> data byte(s) through SPI bus.
$000330A8 TSYSFSSPI__TRANSFER, line 263 of /home/debian/lazarus/pxl/Source/PXL.Sysfs.SPI.pas
$00032F54 TSYSFSSPI__WRITE, line 241 of /home/debian/lazarus/pxl/Source/PXL.Sysfs.SPI.pas
Is there some documentation out there on the ioctl call and what the actual parameter means in detail with respect to the BeagleBone processor? The man page states that command is specific to the device.
https://man7.org/linux/man-pages/man2/ioctl.2.html
I'm having trouble figuring out why it fails or more specifically where to look next. I can't step the machine code past the ioctl system call so I'd like to know what is actually going on inside the OS with this call inside the Beagle.
Thanks
John
"ELS! Nothing else works as well for your Lathe"
Automation Artisans Inc.
www dot autoartisans dot com
So to add this so the research I did isn't repeated.
The control message breaks down as follows:
Top two bits are the direction. The 'k' (0x6B) identifies the SPI type. The number of bytes is placed into the 32 bit word with the _IOC_NRSHIFT which in itself is also a macro all defined in the asm generic ioctl.h file.
ret = ioctl(fd, _IOC(_IOC_WRITE,('k'),(1),(8), &mode);
#define _IOC(dir,type,nr,size) \
(((dir) << _IOC_DIRSHIFT) | \
((type) << _IOC_TYPESHIFT) | \
((nr) << _IOC_NRSHIFT) | \
((size) << _IOC_SIZESHIFT))
The shifts are defined to create this and it's quite convoluted to get there.
SPI_IOC_MESSAGE(1) = 40206B00
define _IOC_NRBITS 8
#define _IOC_TYPEBITS 8
/*
* Let any architecture override either of the following before
* including this file.
*/
#ifndef _IOC_SIZEBITS
# define _IOC_SIZEBITS 14
#endif
#ifndef _IOC_DIRBITS
# define _IOC_DIRBITS 2
#endif
#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1)
#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1)
#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1)
#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1)
#define _IOC_NRSHIFT 0
#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS)
#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS)
#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS)
#define _IOC_NRSHIFT 0
#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS)
#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS)
#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS)
--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to the Google Groups "BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beagleboard...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/beagleboard/02a901d74d2a%246b84f600%24428ee200%24%40autoartisans.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/beagleboard/02b401d74d2d%2403af82e0%240b0e88a0%24%40autoartisans.com.
Unlike Delphi or say the 9S12 or PIC debugger the Lazarus shows the source but doesn't seem to have a step ability in machine language. So I can see what it's doing and even the registers but nothing more.
Given that the C code works perfectly and the Pascal stuff sends the same information I suspect the problem isn't with the OS but perhaps pointer formatting or something like that.
Still working on it. Without these kinds of problems I never really learn how things are put together. So it's not a bad thing. Just annoying. The system can send ioctl messages directly as shown in the log. But when using the transfer function it dies.
So something between 2017 when this code was released and now there is something slightly different.
John
To view this discussion on the web visit https://groups.google.com/d/msgid/beagleboard/1121873347.1447636.1621489360355%40mail.yahoo.com.
The latest version of Buster does this when I look for SPI bus ports. The older Stretch version doesn't have the 0.0 and 0.1 and everything is scaled up by 1.
On either system the scope doesn't show any activity on the SPI0 pins. No CS, no CLK no Data Out.
The test program from Exploring Beaglebone with the DI connected to the DO does not behave with the table changed from the output stream to input which makes sense since there isn't any output on the MOSI or MISO pins.
Any suggestions on how to get SPI working?
debian@beaglebone:~$ uname -a
Linux beaglebone 4.19.94-ti-r63 #1buster SMP PREEMPT Fri May 14 16:42:32 UTC 2021 armv7l GNU/Linux
debian@beaglebone:~$ ls -l /dev/spi*
crw-rw---- 1 root spi 153, 0 May 20 17:24 /dev/spidev0.0
crw-rw---- 1 root spi 153, 1 May 20 17:24 /dev/spidev0.1
crw-rw---- 1 root spi 153, 2 May 20 17:24 /dev/spidev1.0
crw-rw---- 1 root spi 153, 3 May 20 17:24 /dev/spidev1.1
debian@beaglebone:~$
debian@ebb:~$ uname -a
Linux ebb 4.14.108-ti-r136 #1stretch SMP PREEMPT Mon Jun 8 15:38:30 UTC 2020 armv7l GNU/Linux
debian@ebb:~$ ls -l /dev/spi*
crw-rw---- 1 root spi 153, 0 May 20 16:45 /dev/spidev1.0
crw-rw---- 1 root spi 153, 1 May 20 16:45 /dev/spidev1.1
crw-rw---- 1 root spi 153, 2 May 20 16:45 /dev/spidev2.0
crw-rw---- 1 root spi 153, 3 May 20 16:45 /dev/spidev2.1
/dev/spi:
total 0
lrwxrwxrwx 1 root root 12 May 20 16:45 0.0 -> ../spidev1.0
lrwxrwxrwx 1 root root 12 May 20 16:45 0.1 -> ../spidev1.1
lrwxrwxrwx 1 root root 12 May 20 16:45 1.0 -> ../spidev2.0
lrwxrwxrwx 1 root root 12 May 20 16:45 1.1 -> ../spidev2.1
debian@ebb:~$
==================================================================================================
debian@beaglebone:~/exploringBB/chp08/spi/spidev_test$ ./spidev_test -D /dev/spidev0.0
spi mode: 0
bits per word: 8
max speed: 500000 Hz (500 KHz)
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00
debian@beaglebone:~/exploringBB/chp08/spi/spidev_test$
Alright.
Doing some more research on the web turned up one page where the user is referencing the original Molloy book and complaining about $SLOTs in chapter six not being relevant but using a current OS which doesn't have $SLOTS. The new edition of the book does not mention $SLOTS but instead config-pin for GPIO management.
The sad thing is that Derek Molloy's book, only in passing refers to enabling the SPI port, and the book, in trying to also deal with the pocket beagle pins leaves out things where repetition is actually beneficial. Maybe somewhere it says that you have to use config-pin to set up SPI. I missed it. I think in Chapter 8 page 363 needs a bit of work.
So here's what I did following part of that web page suggestion on the Buster image:
debian@beaglebone:~/exploringBB/chp08/spi/spidev_test$ config-pin p9.17 spi_cs
Current mode for P9_17 is: spi_cs
debian@beaglebone:~/exploringBB/chp08/spi/spidev_test$ config-pin p9.22 spi_sclk
Current mode for P9_22 is: spi_sclk
debian@beaglebone:~/exploringBB/chp08/spi/spidev_test$ config-pin p9.21 spi
Current mode for P9_21 is: spi
debian@beaglebone:~/exploringBB/chp08/spi/spidev_test$ config-pin p9.18 spi
Current mode for P9_18 is: spi
I hadn't realized that this was needed if the spi device was opened as a fille. I assumed opening a /dev/spi0.0 would automatically claim the pins for SPI. So with MOSI connected to MISO and specifying the SPI0 port since SPI1 is used by HDMI I get:
debian@beaglebone:~/exploringBB/chp08/spi/spidev_test$ ./spidev_test -D /dev/spidev0.0
spi mode: 0
bits per word: 8
max speed: 500000 Hz (500 KHz)
FF FF FF FF FF FF
40 00 00 00 00 95
FF FF FF FF FF FF
FF FF FF FF FF FF
FF FF FF FF FF FF
DE AD BE EF BA AD
F0 0D
And that data matches what the scope tells me in the attached photo. Clock is yellow trace. MOSI is Blue. Green is CS.
Oh and none of this explains why the ioctl regardless of C or Pascal can't handle more than 4096 data bytes while the Python code can when sending a large bitmap to the SPI port. Nor why, according to this web site
https://learn.adafruit.com/setting-up-io-python-library-on-beaglebone-black/spi
nothing is said about config-pin operations so the python library must do this automatically?
Now to try this on the Stretch OS based Beagle.
John
From: beagl...@googlegroups.com [mailto:beagl...@googlegroups.com] On Behalf Of John Dammeyer
Sent: May-20-21 5:43 PM
To: beagl...@googlegroups.com
--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to the Google Groups "BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beagleboard...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/beagleboard/034801d74dda%2435a8c060%24a0fa4120%24%40autoartisans.com.
--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to the Google Groups "BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beagleboard+unsub...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/beagleboard/v2pgag101omfhqgj1h5p4o03b3ilskegli%404ax.com.
So I've solved the problem with the
ESysfsSPITransfer: Cannot transfer <1> data byte(s) through SPI bus.
The C versions with the spi_ioc_transfer structure declared inside the transfer() function work on both the Beagle and Pi3.
Here's the BBB version from and you can see the code is identical for both the Pi and the Beagle.
https://github.com/derekmolloy/exploringBB/blob/version2/chp08/spi/spidev_test/spidev_test.c
==============================================================================================
uint8_t rx[ARRAY_SIZE(tx)] = {0, };
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = ARRAY_SIZE(tx),
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
};
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
pabort("can't send spi message");
==============================================================================
Here's the Pi version from exploringPi Chp08 spidev_test.c
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = ARRAY_SIZE(tx),
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
};
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
pabort("can't send spi message");
==============================================================================
Both identical.
So now let's look at the Lazarus Free Pascal version from inside the pxl library PXL.Sysfs.SPI and see if there's anything different.
Data.tx_buf := PtrUInt(WriteBuffer);
Data.rx_buf := PtrUInt(ReadBuffer);
Data.len := BufferSize;
Data.delay_usecs := 0;
Data.speed_hz := FFrequency;
Data.bits_per_word := FBitsPerWord;
Res := fpioctl(FHandle, SPI_IOC_MESSAGE(1), @Data);
if Res < 0 then
raise ESysfsSPITransfer.Create(Format(SCannotSPITransferBytes, [BufferSize]));
==============================================================================
Doesn't seem like there's any difference yet the Lazarus version fails. After more searching on the net I stumbled onto a posting in a Pi forum where someone else was having similar problems. A reply to his question was an example that was working but unfortunately that link was "404 not found". However the original poster did state what the difference between the working code and his and his solution.
Now the Pascal version succeeds without an error. I've yet to check if SPI data is showing up in hardware but I imagine it will. The good thing is the runtime error is now gone.
FillByte(Data, Sizeof(Data), 0); // Without this FillByte() fpioctl fails.
Data.tx_buf := PtrUInt(WriteBuffer);
Data.rx_buf := PtrUInt(ReadBuffer);
Data.len := BufferSize;
Data.delay_usecs := 0;
Data.speed_hz := FFrequency;
Data.bits_per_word := FBitsPerWord;
Res := fpioctl(FHandle, SPI_IOC_MESSAGE(1), @Data);
if Res < 0 then
raise ESysfsSPITransfer.Create(Format(SCannotSPITransferBytes, [BufferSize]));
It's likely the C compiler clears this structure when it's declared or extends 0's out on an assignment that isn't done by the FreePascal compiler. And that it was required in that Pi forum posting for C code suggests it's perhaps even somewhat random. Compiler flags maybe?
So that's the solution for this run time error. Clear the data structure before initializing parameters and calling ioctl().
If I get a chance today I'll see if SPI data is actually coming out of the processor but based on the sample application behavior it likely is.
John
I agree, the C code uses the equivalent of the WITH statement in Pascal to assign parameters during structure declaration. Once you 'get' how it works it's fairly readable.
My understanding is both systems place the variables on the heap. Only the small micro-controllers with limited stack space (recall some of the PIC16 series had a 2 word call stack). Other systems in the micro-controller area might limit the stack to 256 bytes due to paging schema.
The record (struct) is essentially the same in C or Pascal.
spi_ioc_transfer = record
tx_buf: UInt64;
rx_buf: UInt64;
len: LongWord;
speed_hz: LongWord;
delay_usecs: Word;
bits_per_word: Byte;
cs_change: Byte;
pad: LongWord;
end;
The C one with some extra information about the requirements of the structure is here:
https://github.com/spotify/linux/blob/master/include/linux/spi/spidev.h
In both cases the requirement is that they are 32 bytes in length hence the pad at the end.
Filling it with zero's first implies that the transition of the address of a BYTE buffer to unsigned 64 bit is probably being corrupted in some unexpected way. With Pascal, generally, globals are initialized to 0's as are C variables unless you add the flag to not initialize in the C startup code. Locals on the stack are not for both languages.
The pxl library was last updated in 2017 and there are photos and fritzing diagrams on how to connect hardware so that the image on the displays is created by the example programs (both Pi and BBB). That it worked in 2017 and now doesn't means something in either the OS and the ioctl() interface has changed or the FreePascal compiler is doing something different.
And that other link that I now can't find anymore shows that even for the Pi3 a C program without the fill structure with 0's will fail in exactly the same way. Don't remember the date. May well have been roughly the same revision OS which means the issue might well have been in the ioctl() at the OS level for SPI bus.
As the attached screen shot shows, SPI packets are now longer than 1 or 2 bytes on a Beaglebone with code written in Pascal. It's finally behaving.
For now I'm going to consider this 'fixed' and I will pass on the information to the pxl library source.
BTW. For the Pi to make this work I have to either run it with sudo from the command line or run Lazarus with sudo. The help everyone provided on the Beagle to make my user part of the gpio group means the code can run and be debugged from within the IDE.
Thanks
John
> -----Original Message-----
> From: beagl...@googlegroups.com [mailto:beagl...@googlegroups.com] On Behalf Of Dennis Lee Bieber
> Sent: May-25-21 10:39 AM
> To: Beagleboard
> Subject: [beagleboard] Re: ioctl messages to Beagle SPI port.
> --
> For more options, visit http://beagleboard.org/discuss
> ---
> You received this message because you are subscribed to the Google Groups "BeagleBoard" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to beagleboard...@googlegroups.com.
> To view this discussion on the web visit