Page 1 of 1

Porting Arduino pro mini code to esp32 (playing with serial communication)

Posted: Thu Oct 22, 2020 4:13 pm
by Puma_FPV
Hello, for my project I need to communicate with a RF module (R9M from FrSky) with a protocol called PXX or PCM. After some time I understood how it worked and also found a library that could be used. Saddly this library is made for Arduino pro mini and calls registers and buffers in two functions... The rest is fine.
Here is the code that is causing me problems and that I would like to port to esp32

Code: Select all

void USART_Init(long baud)
{
    int _baud = (16000000 / (2 * baud)) - 1;

    UBRR0 = 0;

    /* Setting the XCKn port pin as output, enables master mode. */
    //XCKn_DDR |= (1<<XCKn);
    //DDRD = DDRD | B00000010;

    /* Set MSPI mode of operation and SPI data mode 0. */
    UCSR0C = (1<<UMSEL01)|(1<<UMSEL00)|(1<<UDORD0);

    /* Enable receiver and transmitter. */
    UCSR0B = (1<<TXEN0);
    /* Set baud rate. */
    /* IMPORTANT: The Baud Rate must be set after the transmitter is enabled */
    UBRR0 = _baud;
}

void USART_Send(uint8_t data) 
{
    /* Put data into buffer, sends the data */
    UDR0 = data;

    //Wait for the buffer to be empty
    while ( !( UCSR0A & (1<<UDRE0)) );
}
if anyone could help me I could really appreciate it :)

Re: Porting Arduino pro mini code to esp32 (playing with serial communication)

Posted: Fri Oct 23, 2020 7:04 am
by Puma_FPV
Here is the whole code for those who wants to know (the .h file is only about declaration and useless to understanding the code)

Code: Select all

#include <Arduino.h>
#include "PXX.h"

#define PPM_CENTER                          127    //1500
#define PPM_LOW                             0     //817
#define PPM_HIGH                            255    //2182
#define PPM_HIGH_ADJUSTED                   (PPM_HIGH - PPM_LOW)
#define PXX_CHANNEL_WIDTH                   2048
#define PXX_UPPER_LOW                       2049
#define PXX_UPPER_HIGH                      4094
#define PXX_LOWER_LOW                       1
#define PXX_LOWER_HIGH                      2046

#define RX_NUMBER 0
#define FAIL_SAFE 0
#define BIND 0

const uint16_t CRC_Short[] =
{
   0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
   0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7
};

uint16_t CRCTable(uint8_t val)
{
	return CRC_Short[val&0x0F] ^ (0x1081 * (val>>4));
}


void PXX_Class::crc( uint8_t data )
{
    pcmCrc = (pcmCrc<<8) ^ CRCTable((pcmCrc>>8)^data);
}

void USART_Init(long baud)
{
    int _baud = (16000000 / (2 * baud)) - 1;

    UBRR0 = 0;

    /* Setting the XCKn port pin as output, enables master mode. */
    //XCKn_DDR |= (1<<XCKn);
    //DDRD = DDRD | B00000010;

    /* Set MSPI mode of operation and SPI data mode 0. */
    UCSR0C = (1<<UMSEL01)|(1<<UMSEL00)|(1<<UDORD0);

    /* Enable receiver and transmitter. */
    UCSR0B = (1<<TXEN0);
    /* Set baud rate. */
    /* IMPORTANT: The Baud Rate must be set after the transmitter is enabled */
    UBRR0 = _baud;
}

void USART_Send(uint8_t data) 
{
    /* Put data into buffer, sends the data */
    UDR0 = data;

    //Wait for the buffer to be empty
    while ( !( UCSR0A & (1<<UDRE0)) );
}

void PXX_Class::begin()
{
    USART_Init(125000);
}

void PXX_Class::putPcmSerialBit(uint8_t bit)
{
    serialByte >>= 1;
    if (bit & 1)
    {
        serialByte |= 0x80;
    }

    if (++serialBitCount >= 8)
    {
        pulses[length++] = serialByte;
        serialBitCount = 0;
    }
}

// 8uS/bit 01 = 0, 001 = 1
void PXX_Class::putPcmPart(uint8_t value)
{
    putPcmSerialBit(0);

    if (value)
    {
        putPcmSerialBit(0);
    }

    putPcmSerialBit(1);
}

void PXX_Class::putPcmFlush()
{
    while (serialBitCount != 0)
    {
        putPcmSerialBit(1);
    }
}

void PXX_Class::putPcmBit(uint8_t bit)
{
    if (bit)
    {
        pcmOnesCount += 1;
        putPcmPart(1);
    }
    else
    {
        pcmOnesCount = 0;
        putPcmPart(0);
    }

    if (pcmOnesCount >= 5)
    {
        putPcmBit(0);                                // Stuff a 0 bit in
    }
}

void PXX_Class::putPcmByte(uint8_t byte)
{
    crc(byte);

    for (uint8_t i=0; i<8; i++)
    {
        putPcmBit(byte & 0x80);
        byte <<= 1;
    }
}

void PXX_Class::putPcmHead()
{
    // send 7E, do not CRC
    // 01111110
    putPcmPart(0);
    putPcmPart(1);
    putPcmPart(1);
    putPcmPart(1);
    putPcmPart(1);
    putPcmPart(1);
    putPcmPart(1);
    putPcmPart(0);
}

void PXX_Class::prepare(int16_t channels[16], int16_t rx_number, byte bind)
{
    uint16_t chan=0, chan_low=0;

    length = 0;
    pcmCrc = 0;
    pcmOnesCount = 0;

    /* Preamble */
    //putPcmPart(0);
    //putPcmPart(0);
    //putPcmPart(0);
    //putPcmPart(0);

    /* Sync */
    putPcmHead();

    // Rx Number
    putPcmByte(rx_number);

    // FLAG1 - Fail Safe Mode, nothing currently set, maybe want to do this
    putPcmByte(0x00);

    // FLAG2
    putPcmByte(0x00);

    // PPM
    for (int i=0; i<8; i++)
    {

        int channelPPM = channels[(sendUpperChannels ? (8 + i) : i)];
        float convertedChan = ((float(channelPPM) - float(PPM_LOW)) / (float(PPM_HIGH_ADJUSTED))) * float(PXX_CHANNEL_WIDTH);
        chan = limit((sendUpperChannels ? PXX_UPPER_LOW : PXX_LOWER_LOW), convertedChan, (sendUpperChannels ? PXX_UPPER_HIGH : PXX_LOWER_HIGH));

        if (i & 1)
        {
            putPcmByte(chan_low); // Low byte of channel
            putPcmByte(((chan_low >> 8) & 0x0F) | (chan << 4));  // 4 bits each from 2 channels
            putPcmByte(chan >> 4);  // High byte of channel
        }
        else
        {
            chan_low = chan;
        }
    }
    
    putPcmByte(0x40); //10mw EU

    // CRC16
    chan = pcmCrc;
    putPcmByte(chan>>8);
    putPcmByte(chan);

    // Sync
    putPcmHead();
    putPcmFlush();
}

void PXX_Class::send()
{
    for(int i = 0; i < length; i++)
    {
        USART_Send(pulses[i]);
    }

    sendUpperChannels = !sendUpperChannels;
}

uint16_t PXX_Class::limit(uint16_t low, uint16_t val, uint16_t high)
{
    if(val < low)
    {
        return low;
    }

    if(val > high)
    {
        return high;
    }

    return val;
}

PXX_Class PXX;