At the point where I last wrote about my RFID code, I had ported the Arduino library back to C. I was able to perform the ISO 14443-A Anti Collision. That’s the point where some of the other things I had in mind come to play. While I removed the Arduino code, I had hard coded it to use the GPIO and SPI on my Blue Pill. I wish to replace it with a hardware abstraction layer of my own. This hardware abstraction layer then would call in manufacturer specific code, (eg. STM32Cube*, nrfx).
One thing I wish to point out, the SPI bus can be shared amongst devices. It is through the Slave Select pin that determines which device is selected. The simplest approach would be just pulling the pin low and start communicating. However, different devices have different properties, such as the maximum clock speed. Rather then using the lowest common speed, one could reconfigure the clock for each device to have optimum speed. Furthermore, SPI devices might run in a different SPI mode, which refers to the used clock polarity and phase. While most SPI devices I’ve encountered so far run in SPI mode 0, one should be aware this does not have to be the case.
So, basically, I have created a struct to contain those settings like the speed and mode for the device. Furthermore, I keep track of the pins to use, such as the Slave Select pin. I also keep a Command/Data pin, as commonly found on SPI controlled displays. Other pins that might come on handy would be interrupt and reset lines.
The microcontrollers I am mostly involved with are in the STM32 and the nRF5x families. I use the manufacturer provides (BSD licensed) hal libraries. That is for the STM32 the STM32Cube*, where * is the device family, such as F0,F1….L0, L1, etc. For the nRF5x family I use the nrfx library.
Looking at GPIO abstraction
// STM32Cube* void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState); // nrfx NRF_STATIC_INLINE void nrf_gpio_pin_write(uint32_t pin_number, uint32_t value);
We see different styles between the Hardware Abstraction Layers from different manufacturers. This is kinda what I am getting at, an Abstraction Layer for Hardware Abstraction Layers. And what to call it? Hardware Abstraction Layer Abstraction Layer, HALAL, would come to mind, but that word already has a meaning in religious context, so I’d better not. At the time of writing, I am using libhalglue, but I might rename it if I can think of something better. Well, let’s get back to what we see here. The implementation by ST takes three parameters, while the implementation by Nordic only takes two. For the ST implementation, we take a port, a pin, and a state. Nordic’s implementation only takes a pin and a state.
ST takes a pointer to the GPIO port, the memory address where (at some offset) the port value is written. The pin value given is as the value to be written to the registers. A bit set at the pin number within the port, (eg, to set pin 4, one sets 1<<4). This would allow to set multiple pins at once. Nordic's implementation takes a single pin number. Pin numbers are counting though ports. On nRF5x hardware, we have a port with 32 pins. We have Px.00 to Px.31, For P0 we get P0.31, we got pin number 31. Then when we get to the next port, at pin P1.00, we get pin number 32. So to derive the port, we divide the pin by 32, and to get the pin within the port, we take the modulus 32. One advantage of this approach is that one would only needs one variable to identify a pin, rather then two variables. I have written an GPIO abstraction layer around ST's HAL to behave more like Nordic's HAL by using a single number for a pin. As pins on an ST GPIO port have 16 pins, we get 0 .. 15 to mean PA0..PA15, 16..31 to mean PB0..PB15, etc. Being able to identify GPIO pins with a single number allows it easier for an abstraction for the SPI layer. There is more to be done. There is always more to be done, but with all we have now, the SSD1331 and the MFRC522 on the same SPI but, my abstraction layer changing the SPI clock speed when communicating with each, and controlling the GPIO lines, I thought it was time to look at the CLRC663. As the module I am using uses the same pinout, it is an easy swap, electronically. I have adjusted the transport layer, at least for SPI, and have written out the registers. However, let's begin setting up communication. To test communication I start with reading out the Version register. Other then that, nothing done yet. And now... I was not getting results, nope, nothing. Well... time to dig the data sheets, and there it was, the POLARITY of the RESET pin was reversed. The MFRC522 was an active low reset pin. One has to pull the pin low to reset the device, and during operation it is high. This is the common, active low, reset pin as found on many devices. However, the CLRC663 has an active high reset pin. One has to keep it low during operation. Now I am thinking, do I need to encode polarity in my GPIO abstraction layer? Once that was resolved, reading the version register worked as expected. Then I proceeded by porting the code for the RC52x to the RC66x, by looking what registers where written to on the RC52x and match it to an RC66x register. As fas as that goes, I want to be able to do the Anti Collision, as a Proof of Concept. After that, I might look into some refactoring of the whole. Even though the either Arduino, or my ported version, work fine, I am not quite happy with some design decisions. Like, turning the antenna on during initialisation. I wish to make such thing an explicit action. Furthermore, as the RC66x supports multiple card types, there must be some support there as well, to begin API-wise, even when only ISO-14443-A support is present, I should refactor the APIs such that it allows for multiple card types.