So we're trying to store bytes (from an A/D converter) of data into a SanDisk 1Gb microSD card from a LPC1769 microcontroller board using the on-board SPI protocol. I know how all that stuff works, but I have no idea how to start working with the microSD card--I've seen various references to CMD0 and what not, but I don't know where to find this library or how to properly incorporate it into the C compiler for the board.
All I need is to figure out how to start the connection properly and then how to read and write data into the card at designated blocks.
void write(int data, int block)
int read(int block) << if there is a way to do this simply with a library of pre-defined microSD functions, that would be AWESOME
FatFS is a simple FAT filesystem that has been ported to many microcontrollers (perhaps it's already available for yours) that also provides the low level writing to the SD card (and you can use that as a reference for your working.. It lets you write actual files to the SD card that you can then put on a computer and read/write. This ends up working very nicely.
http://bikealive.nl/fatfs.html
There is also a nice App Note from TI that has some basic API to do this:
http://www.ti.com/general/docs/lit/getliterature.tsp?literatureNumber=slaa281b&fileType=pdf
Although it's for the MSP430, it can clearly show you what kind of register accesses you need to write the bytes yourself and you can implement the equivalent thing.
Finally, Olimex have boards with similar microcontrollers and SD cards, and you can see what they do:
https://www.olimex.com/Products/ARM/NXP/LPC1766-STK/
I found more information specifically for your microcontroller (though the suggestions above work well as well):
Two app notes from NXP on doing what you're asking for:
AN10916 - "FAT library EFSL and FatFs port on NXP LPC1700"
AN11070 - "Accessing SDC/MMC card using SPI/SSP on LPC1700".
With this you should be all set.
Related
I am writing a kernel module to read and write to SPI device (CC1200).
My linux device does not have native SPI, so I am trying to bit-bang the bus.
I found that linux has built-in bitbang code (linux/spi/spi_bitbang.h), but I am confused how to set it up. It needs structs as spi_device and spi_master, each requiring struct device, which requires structs as kobject and many many more, most of them I have no idea what to do with them, and how they are needed for simple bit-banging.
I have looked online for examples, but i found literally none. Not a single use of the included bitbang code, only some references that it is "easy"
I will be very thankful for any help, maybe the bitbang lib is not even the good path. Maybe I can write my own (how to do it efficiently? I have 4 cores, but it is running lots of stuff in the background)
Thanks
Because of the nature of SPI where data is clocked and read by the master there is nothing wrong with the bit banging driver for the master, as the slave should not relay on a stable clock. But of course it depends on the slave device if this will work in practice or not.
If you are using the linux kernel there is no need to implement your own bit-banging driver as there already is one spi-gpio.c
My guess how to get it up and running would be by defining what GPIO pins to use in the devicetree, then the driver would be able to act as any of the other physical layer drivers.
I had a quick glance at drivers/spi/spi-gpio.c source code, and there is even a short user guide how to directly access the GPIO pins inline without using the generic GPIO layer overhead.
/*
* Because the overhead of going through four GPIO procedure calls
* per transferred bit can make performance a problem, this code
* is set up so that you can use it in either of two ways:
*
* - The slow generic way: set up platform_data to hold the GPIO
* numbers used for MISO/MOSI/SCK, and issue procedure calls for
* each of them. This driver can handle several such busses.
*
* - The quicker inlined way: only helps with platform GPIO code
* that inlines operations for constant GPIOs. This can give
* you tight (fast!) inner loops, but each such bus needs a
* new driver. You'll define a new C file, with Makefile and
* Kconfig support; the C code can be a total of six lines:
*
* #define DRIVER_NAME "myboard_spi2"
* #define SPI_MISO_GPIO 119
* #define SPI_MOSI_GPIO 120
* #define SPI_SCK_GPIO 121
* #define SPI_N_CHIPSEL 4
* #include "spi-gpio.c"
*/
PS are you sure your platform does not have spi, all the SoC I have worked with from HiSilicon have had one. I would double check this first
EDIT: It seems they've changed the interface and you can't do this any more in modern kernels from 4.19 and later, for the same reason you can't do it with i2c.
https://forum.openwrt.org/t/i2c-kernel-4-19-i2c-gpio-custom/49213
I will leave this here for now, perhaps it will be useful. I myself am using older kernels for home automation but it's on a private network.
My original answer:
Whilst you can probably get this working by hacking your own kernel module together instead you can investigate spi-gpio-custom, simply load the module and pass the pins you want to use as parameters, you can do everything at run-time and don't need to 'compile-in' the pins you want to use. You can find this module in the OpenWrt project:
https://github.com/openwrt/openwrt/tree/openwrt-19.07/package/kernel/spi-gpio-custom/src
I would expect that to give you some kind of SPI device when initialised that you can write to from user-space. Note that I haven't used this module myself, but some time ago I've used the i2c counterpart which works in similar way.
Alternatively, you could consider introducing an Arduino to talk to your SPI bus then translate the SPI data into something your Linux device understands.
The Nano board will probably do what you need and costs peanuts if you don't want to make up your own board.
Then for the interface, you would then have a few choices: USB, UART, i2c or 1wire even a parallel interface if you have the pins. There is a 1-wire slave library on github for instance: https://github.com/smurfix/owslave.
I've just read that SD cards all have some DRM code that will prevent reads or writes of "protected content".
As my code will sometimes use SD cards for storage, what is the practical consequence of the DRM? What steps (if any) do I need to take to avoid writing out files that might not be read back?
It is not so simple. DRM functions use separate storage from non-protected area. There are special SD commands for DRM and in addition, there is "secret" part of SD Card spec. Buy membership for $1000 at sdcard.org and get the info :) In short - DRM features can be used mostly by special hardware (microcontroller connected to SD slot), not simple PC software.
I have been playing with creating sounds using mathematical wave functions in C. The next step in my project is getting user input from a MIDI keyboard controller in order to modulate the waves to different pitches.
My first notion was that this would be relatively simple and that Linux, being Linux, would allow me to read the raw data stream from my device like I would any other file.
However, research overwhelmingly advises that I write a device driver for the MIDI controller. The general idea is that even though the device file may be present, the kernel will not know what system calls to execute when my application calls functions like read() and write().
Despite these warnings, I did an experiment. I plugged in the MIDI controller and cat'ed the "/dev/midi1" device file. A steady stream of null characters appeared, and when I pressed a key on the MIDI controller several bytes appeared corresponding to the expected Message Chunks that a MIDI device should output. MIDI Protocol Info
So my questions are:
Why does the cat'ed stream behave this way?
Does this mean that there is a plug and play device driver already installed on my system?
Should I still go ahead and write a device driver, or can I get away with reading it like a file?
Thank you in advanced for sharing your wisdom in these areas.
Why does the cat'ed stream behave this way?
Because that is presumably the raw MIDI data that is being received by the controller. The null bytes are probably some sort of sync tick.
Does this mean that there is a plug and play device driver already installed on my system?
Yes.
However, research overwhelmingly advises that I write a device driver for the MIDI controller. The general idea is that even though the device file may be present, the kernel will not know what system calls to execute when my application calls functions like read() and write().
<...>
Should I still go ahead and write a device driver, or can I get away with reading it like a file?
I'm not sure what you're reading or how you're coming to this conclusion, but it's wrong. :) You've already got a perfectly good driver installed for your MIDI controller -- go ahead and use it!
Are you sure you are reading NUL bytes? And not 0xf8 bytes? Because 0xf8 is the MIDI time tick status and is usually sent periodically to keep the instruments in sync. Try reading the device using od:
od -vtx1 /dev/midi1
If you're seeing a bunch of 0xf8, it's okay. If you don't need the tempo information sent by your MIDI controller, either disable it on your controller or ignore those 0xf8 status bytes.
Also, for MIDI, keep in mind that the current MIDI status is usually sent once (to save on bytes) and then the payload bytes follow for as long as needed. For example, the pitch bend status is byte 0xeK (where K is the channel number, i.e. 0 to 15) and its payload is 7 bits of the least significant byte followed by 7 bits of the most significant bytes. Thus, maybe you got a weird controller and you're seeing only repeated payloads of some status, but any controller that's not stupid won't repeat what it doesn't need to.
Now for the driver: have a look at dmesg when you plug in your MIDI controller. Now if your OSS /dev/midi1 appears when you plug in your device (udev is doing this job), and dmesg doesn't shoot any error, you don't need anything else. The MIDI protocol is yet-another-serial-protocol that has a fixed baudrate and transmits/receives bytes. There's nothing complicated about that... just read from or write to the device and you're done.
The only issue is that queuing at some place could result in bad audio latency (if you're using the MIDI commands to control live audio, which I believe is what you're doing). It seems like those devices are mostly made for system exclusive messages, that is, for example, downloading some patch/preset for a synthesizer online and uploading it to the device using MIDI. Latency doesn't really matter in this situation.
Also have a look at the ALSA way of playing with MIDI on Linux.
If you are not developing a new MIDI controller hardware, you shouldn't worry about writing a driver for it. It's the user's concern installing their hardware, and the vendor's obligation to supply the drivers.
Under Linux, you just read the file. Now to interpret and make useful things with the data.
I need a method to perform the following task, suppose if I have a computer with k (k is large) number of Ethernet interfaces. I want to have a method to identify which identifier (em0) is assigned to which physical interface.
The only "easy" method that I came up is to blink the LED light on the physical interface.
For example
etherblink em0
Would flash the link or the activity LED on the physical Ethernet interface that is assigned to em0.
I know on linux there is the ethertool, but that doesn't work with FreeBSD. As well as there is the LED driver on FreeBSD, but that only support limited number of Ethernet modules.
Any ideas? I thought about binding a socket to the interface and write to the socket, but that didn't work.
C or Perl
Tough I have not done this, but, according to FreeBSD handbook, it's possible to bind specific driver node to specific hardware IRQ using kernel configuration hints. See device.hints(5) and FreeBSD network setup to see how to locate each Ethernet device IRQ.
Assume the interface in question is fxp0... run this as root
use strict;
my $intf = "fxp0";
while (1) {
foreach my $state (qw/up down/) {
system("ifconfig $intf $state\n");
sleep 3;
}
}
I assume you won't care about transfering data through the interface while it's blinking...
Sadly I did not find a general solution to this problem, however, from my research (by reading the change log of FreeBSD 8.2, and from the forums) It seems that:
"some cards blink the LEDs on access, so pings could make a repeated pattern.
The LEDs might even go off if the card is downed with ifconfig(8)."
Particularly em and igb interfaces, as stated by:
"The em(4) and igb(4) drivers now support the led(4) interface via /dev/led/emN and
/dev/led/igbN for identification LED control. The following command line makes the
LED blink on em0:[r211241]" (FreeBSD 8.2 Release changelog)
However I do not have the hardware to test this. What I did end up doing was rewritten the Ethernet driver for the interface that I am using to support the LED hardware feature.
I'm customising Linux for an ARM9 Atmel AT91SAM960 board.
In the device file Atmel named all the USART the same atmel_usart. Of course with id enumeration:
static struct platform_device at91sam9260_uart0_device = {
.name = "atmel_usart",
.id = 1,
.dev = { ...}
}
According to the Linux Device model, all these devices (5 UARTS on a SAM9260) would be bind to the driver named atmel_usart.
I don't want to set a TTYS driver on all UARTS which will be registerd. I have several own drivers which serve for different specialised purposes (LON, RS-485 etc.) I want the control which driver does serve a certain USART. So what could I do:
The Atmel device files are unsatisfiable and I can do it better. So I rename (patch) the devices in the device file. However, in case I want a TTYS driver on UART4 I would be in trouble.
I manipulate (patch) the device file,
so that I'm able the access the
structures platform_device. I could
change their names before I would
register them. But as far as I
understood the idea of the Linux Driver Model,
devices should be
registered early during boot-up but the binding to a driver follows .... later.
I could write a driver, which has an
alias name and which would be binded
to a specific bus_Id ->
atmel_usart.4. Can I really?
What solutions else exist. I want to touch a minimal set of Kernel files but I want all the freedom possible?
Addendum what freedom means to me: I can specify at runtime how the UARTS can be used
with the Atmel-Serial driver (ttyS)
with my own drivers
It means also, that changes to the kernel source are minimal.
I built my own line discipline drivers. You can build them as kernel modules and attach them to the UARTs at runtime. No changes to the Linux source are necessary.
Any funny timing or control stuff can be done through ioctl(). Specifically, I implemented a timing-sensitive RS-485 protocol in this way.
When I did this (Linux 2.6.17) there was no dynamic registration mechanism, so I overwrote the existing line disciplines. The Linux code is (was) pretty straightforward, and I was satisfied that this would be a safe thing to do.
Your problem is quite easily solved. The 5 UART devices are presently registered at kernel startup and their function is locked. This is now how it normally works for PCI or USB devices, right? So what you need to do is pull the device registration out of the startup code and register it dynamically. You can even register/unregister as needed.
at91_register_uart() is being called from your board file for every UART that needs registered. at91_add_device_serial() will then platform_device_register all those you what setup. One solution is to let at91_register_uart() be called for all 5 UARTS, but then remove the call to at91_add_device_serial() from your board. You can then make it an exported function that can be called by your loadable drivers. You can even add an argument to it (int) so that instead of looping on all UARTS, you can select which ones to register individually. You can also mirror this function by making one that unregisters the devices.
NOTE: I think you'll need to always leave one UART dedicated as your console, if you are using one that way. You could probably hide that in the exported function by only allowing index 0->3 as in input and then mapping 0->3 to 0-4, skipping the UART that you want to use for console.