Problem when reading a SPI register using mmap

I would like to use SPI using mmap without sysfs.

So I tried to run following code to read SPI registers.
I could get pointer of SPI register but my Jetson NANO topped when reading CMD1 register.
Is there an expert to know why Jetson stopped?

// code

#define SPI_1 0x7000d400 // base address of SPI1

struct SPI_mem {
uint32_t CMD1; // 0x00 offset
uint32_t CMD2; // 0x04 offset

int main(void)
SPI_mem volatile *spi_mem;
void *base;

int fd = open(“dev/mem”, O_RDWR | O_SYNC);

int pagesize = getpagesize();
int pagemask = pagesize -1;

base = mmap(0, pagesize, PROT_READ| PROT_WRITE, MAP_SHARED, fd, (SPI_1 & ~pagemask));
spi_mem = (SPI_mem volatile *) ((char *)base + (SPI_1 & pagemask));

printf(“ptr: %p \n”, spi_mem);
printf(“COMMAND: %08X \n”, spi_mem->CMD1); // Jetson stopped this line

return 0;

Please use spidev utility to access from userspace. For example

runtime_pm is enabled. controller is mostly power off or clock gated, then system will hang like you are seeing

Thanks for kind answer.

I already tried user space SPI interfacing method. It worked well.
But my application has a real time issue. So I use RT preempt patched kernel.
In this case when thread go into kernel space, I can’t be sure when it come out.
The performance of user space SPI interfacing was not time deterministic.
So, I would like to develop simple user space SPI driver.
In the case of GPIO, I could developed user space GPIO driver using mmap.

I would suggest to implement an IOCTL for your function in the SPI driver and have user space to send the IOCTL to handle it.

Thanks for your suggestion.

When I used ioctl call to use spi. the maximum time to be consumed to call ioctl was over than 50ms. (SPI configuration: 16bits, 2MHz speed)
In this case, RT-patched timer accuracy was under 1ms and the priority of spi thread was higher than the priority of timer thread.

I don’t know the reason to consume 50ms.

I could not expect deterministic performance if I use ioctl.
So I tired to use mmap.

//code using ioctl

t1 = t.tv_sec*1000000000+t.tv_nsec; // struct timespec t

ret = ioctl(fd,SPI_IOC_MESSAGE(1), &tr); // tr.len = 3

t2 = t.tv_sec*1000000000+t.tv_nsec; // struct timespec t

printf(“dT: %ld[us]\n”,(t2-t1)/1000);

How are you accounting for the actual wire transfer over SPI for data transfer using devmem read/write?

From Tegra X1 Technical Reference Manual, address map of SPI and its functions are well explained.
And I will use polling method not interrupt method in future my simple SPI user-space driver.

My hardware was already verified by the test of ioctl SPI interface.
If I could access registers of SPI, it is possible to develop simple user-space driver.

For this , I need to be able to access registers of SPI.
for the case of GPIO, it was possible to access registers. but when I apply similar way to SPI, Jetson hang.

you have to make sure that controllers power and clock is always on for you to write to the controller and do programming.

Hi robotchip,
In the case of mmap to gpio, what was the latency time ? and can you post your code for mmap to the gpio’s ?