Ratio Packets: Part 2 Raspberry Pi - Deciphering the GPIO Address and Seeking 1.7 King Ratios.
Ratio Packets: Part 2 Raspberry Pi - Deciphering the GPIO Address and Seeking 1.7 King Ratios.
In the first article - the basic framework of a packet system that uses king bits that have a timing size of 1.7 that of a normal bit - to indicate the packet header and to indicate the size of the following data.
Mapping the Raspberry Pi GPIO Addresses:
- It is not as straight-forward as you might think. The address of a GPIO pin dynamically changes and one must read and decode it at run time:
- BCOM2835.c does this inside its base function at init time - the code base is located at: https://www.airspayce.com/mikem/bcm2835/
- The debug function of BCOM2835.c doesn't actually work - it produces spurious addresses:
- Inside the bcm2835_init(void)
- Each time you run a raspberry pi application the actual GPIO pin address will change:
#define BMC2835_RPI2_DT_FILENAME "/proc/device-tree/soc/ranges"
int bcm2835_init(void)
/* Figure out the base and size of the peripheral address block
// using the device-tree. Required for RPi2/3/4, optional for RPi 1
*/
if ((fp = fopen(BMC2835_RPI2_DT_FILENAME , "rb")))
{
unsigned char buf[16];
uint32_t base_address;
uint32_t peri_size;
if (fread(buf, 1, sizeof(buf), fp) >= 8)
{
base_address = (buf[4] << 24) |
(buf[5] << 16) |
(buf[6] << 8) |
(buf[7] << 0);
peri_size = (buf[8] << 24) |
(buf[9] << 16) |
(buf[10] << 8) |
(buf[11] << 0);
if (!base_address)
{
/* looks like RPI 4 */
base_address = (buf[8] << 24) |
(buf[9] << 16) |
(buf[10] << 8) |
(buf[11] << 0);
peri_size = (buf[12] << 24) |
(buf[13] << 16) |
(buf[14] << 8) |
(buf[15] << 0);
}
/* check for valid known range formats */
if ((buf[0] == 0x7e) &&
(buf[1] == 0x00) &&
(buf[2] == 0x00) &&
(buf[3] == 0x00) &&
((base_address == BCM2835_PERI_BASE) || (base_address == BCM2835_RPI2_PERI_BASE) || (base_address == BCM2835_RPI4_PERI_BASE)))
{
bcm2835_peripherals_base = (off_t)base_address;
bcm2835_peripherals_size = (size_t)peri_size;
if( base_address == BCM2835_RPI4_PERI_BASE )
{
pud_type_rpi4 = 1;
}
}
}
fclose(fp);
First run for RPI_BPLUS_GPIO_J8_03
Second run for RPI_BPLUS_GPIO_J8_03
If you look at the data sheet for a BCOM2835 it will specify hard addresses as in:
Once we finally get past all this (and we have close to direct access) to driving a pin we would like a function that has:
- Pretty fast modulation rate (1Mhz)
- Accurate 1.7 ratio
- std_pulse = NNN , king_pulse = NNN * 1.7
while (1)
{
__sync_synchronize();
*setaddr = 1 << shift;
__sync_synchronize();
for (uint t = 0; t < std_pulse; t++)
{
asm("nop;");
}
__sync_synchronize();
*clraddr = 1 << shift;
__sync_synchronize();
for (uint t = 0; t < king_pulse; t++)
{
asm("nop;");
}
}
After trying a bunch of values by manual tuning we come up with an acceptable ratio:
In the end we find a 150 / 263 ratio gives us pretty good results. A few issues is the modulation rate of the Std Bit did not come close to the 1Mhz and is overclocked at 1.11627 Mhz.
Next we want to see if we can send (and receive) a header packet and how many devices it can successfully communicate with (rpi-2040, arduino etc).
Naturally it would make sense to pick one of the devices with the lowest clock rate - the arduino pico at 16 Mhz is a good candidate.
The standard 32-bit Rasberry PI OS is not a dedicated RTOS (Real-Time Operating System.) - which infers that various system processes may interrupt the bit signalling loop.
In a test of 20 Million samples at 12 Mhz we could find some instances where the signalling was interrupted.
The natural solution to this is to engineer a packet repeat scheme and employ some basic CRC checksum bits.