Categories
Networking

The End of Endianness

I very much dislike dealing with cross-platform endian issues.   When it comes to defining structures with bitfields–it can sometimes become a pain to order all the fields correctly depending on the platform one is using.

Another headache is dealing with host byte ordering and network traffic on Intel platforms–all that byte swapping!!!

Anyway, I’ve been using some simple functions that allow me to parse the message on the fly while it is still in network byte order with no need for byte swapping or structures with bitfields.

The great thing about this code is that it is cross-platform; absolutely no endian issues to deal with.  The price paid for this portability is execution speed–this code will likely be slower when parsing many fields out of a large message.  But if you only need one or two fields from a large message, then this code will actually be faster than byte swapping the entire message.

Below you will find the bitfield extract code header file, then give a small sample program which uses it, and its corresponding output.

Here’s the bitfieldextract.h header file:

#ifndef __BITFIELDEXTRACT_H__
#define __BITFIELDEXTRACT_H__

#if !defined(WIN32)
typedef unsigned long UINT32;
typedef unsigned short UINT16;
typedef unsigned char UCHAR;
typedef unsigned char *PUCHAR;
typedef char *PCHAR;
#else
#include 
#endif

/*
//
// bfx -- bit field extract
//
// extract up to a 32-bit value at any bit
// offset in a byte array
//
*/
inline UINT32 bfx(
  const PUCHAR cptr,
  UINT32 bit_offset,
  UINT32 bit_len)
{
  /*
  // Portable bit field extract code
  */

  UINT32 byte_off    = ( bit_offset >> 3 );
  UINT32 left_shift  = bit_offset - ( byte_off << 3 );
  UINT32 bytes       = ( left_shift + bit_len + 7 ) >> 3;
  UINT32 right_shift = ( bytes << 3 ) - ( bit_len + left_shift );
  UINT8  cval;
  UINT32 val, i;

  /* grab first byte  and apply shift */
  cval = cptr[byte_off] << left_shift;
  val  = cval;
  bytes -= 1;

  if (bytes) {
    /* shift back high order byte */
    val >>= left_shift;

    /* reset left shift since we did it already */
    left_shift = 0;
  }

  for (i=1;i> right_shift );

    /* reset right shift since we did it already */
    right_shift = 0;
  }

  return val >> ( left_shift + right_shift );
}

/*
// bfxi -- bit field extract and increment
//
// extract up to a 32-bit value at any bit
// offset in a byte array and auto-increment
// the bit offset by the number of bits read
*/
inline UINT32 bfxi(
  const PUCHAR cptr,
  UINT32 &bit_offset,
  UINT32 bit_len)
{
  UINT32 val = bfx(cptr, bit_offset, bit_len);

  bit_offset += bit_len;

  return val;
}

#endif

Here’s a small program that uses it:

#include 
#include "bitfieldextract.h"

using namespace std;

int main(int argc, char* argv[])
{
  UCHAR x[6] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc };
  unsigned int ofs = 0;
  int i;

  cout << "Binary representation of buffer "
    << "[ 0x12 0x34 0x56 0x78 0x9a 0xbc ]:"
    << endl << endl << "  ";

  for (i=0;i<48;i++)
    cout << bfxi(x, ofs, 1);
  cout << endl << endl; 

  cout << "Each 4-bit nibble:"
    << endl << endl << "  ";

  ofs = 0;
  for (i=0;i<12;i++)
    printf("0x%1x ", bfxi(x, ofs, 4));
  cout << endl << endl; 

  ofs = 2;
  cout << " 2 bits at " << ofs << " = ";
  cout << bfxi( x, ofs, 2 ) << endl;
  cout << " 4 bits at " << ofs << " = ";
  cout << bfxi( x, ofs, 4 ) << endl;
  cout << " 6 bits at " << ofs << " = ";
  cout << bfxi( x, ofs, 6 ) << endl;
  cout << " 8 bits at " << ofs << " = ";
  cout << bfxi( x, ofs, 8 ) << endl;
  cout << "10 bits at " << ofs << " = ";
  cout << bfxi( x, ofs, 10) << endl;

  for (i=4;i<=8;i++) {
    ofs = i;
    cout << "32 bits at " << ofs << " = ";
    printf("0x%08x\n", bfxi( x, ofs, 32));
  }
  ofs = 16;
  cout << "32 bits at " << ofs << " = "; 
  printf("0x%08x\n", bfxi( x, ofs, 32));

  return 0;

}

And the associated output:

Binary representation of buffer [ 0x12 0x34 0x56 0x78 0x9a 0xbc ]:

  000100100011010001010110011110001001101010111100

Each 4-bit nibble:

  0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc

 2 bits at 2 = 1
 4 bits at 4 = 2
 6 bits at 8 = 13
 8 bits at 14 = 21
10 bits at 22 = 632
32 bits at 4 = 0x23456789
32 bits at 5 = 0x468acf13
32 bits at 6 = 0x8d159e26
32 bits at 7 = 0x1a2b3c4d
32 bits at 8 = 0x3456789a
32 bits at 16 = 0x56789abc
Categories
Embedded

Enabling UART1 on Rev C2 BeagleBoard

I am updating this post to put the preferred method up front–that is modifying u-boot.

And I’ve expanded it to include:

  • UART1 (/dev/ttyS0) Rx/Tx/CTS/RTS on J5
  • UART2 (/dev/ttyS1) Rx/Tx on J3
  • Other GPIOs as needed

The pin mux can be reconfigured in u-boot (thanks, Antti.)

To do this we edit board/omap3/beagle/beagle.c (changes in bold):

/******************************************************************************
* Routine: set_muxconf_regs
* Description: Setting up the configuration Mux registers specific to the
*        hardware. Many pins need to be moved from protect to primary
*        mode.
*****************************************************************************/
void set_muxconf_regs(void)
{
    MUX_BEAGLE();

    if(beagle_revision_c) {
        MUX_BEAGLE_C();
    }

	/* reset default beagleboard UART configs to avoid conflicts */
    MUX_VAL(CP(UART1_TX),        (IDIS | PTD | DIS | M7)) /*UART1_TX*/
    MUX_VAL(CP(UART1_RX),        (IDIS | PTD | DIS | M7)) /*UART1_RX*/
    MUX_VAL(CP(UART2_RX),        (IDIS | PTD | DIS | M7)) /*UART2_RX*/

    /* reset DSS_DATA[0,1,6,7] lines to UART1 mode */
    MUX_VAL(CP(DSS_DATA0),       (IEN  | PTU | EN  | M2)) /*UART1_CTS*/
    MUX_VAL(CP(DSS_DATA1),       (IDIS | PTD | DIS | M2)) /*UART1_RTS*/
    MUX_VAL(CP(DSS_DATA6),       (IDIS | PTD | DIS | M2)) /*UART1_TX*/
    MUX_VAL(CP(DSS_DATA7),       (IEN  | PTD | EN  | M2)) /*UART1_RX*/

	/* set UART2 lines */
    MUX_VAL(CP(UART2_TX),	     (IDIS | PTD | DIS | M0)) /*UART2_TX*/
    MUX_VAL(CP(MCBSP3_FSX),      (IEN  | PTD | EN  | M1)) /*UART2_RX*/

	/* setup GPIOs */

	/* our (not BB) push buttons */
    MUX_VAL(CP(I2C2_SDA),        (IEN  | PTD | EN  | M4)) /*GPIO_183*/
    MUX_VAL(CP(I2C2_SCL),        (IEN  | PTD | EN  | M4)) /*GPIO_168*/

    /* RYG LEDs */
    MUX_VAL(CP(MMC2_DAT7),       (IDIS | PTD | EN  | M4)) /*GPIO_139*/
    MUX_VAL(CP(DSS_DATA17),      (IDIS | PTD | EN  | M4)) /*GPIO_87*/
    MUX_VAL(CP(MMC2_DAT6),       (IDIS | PTD | EN  | M4)) /*GPIO_138*/

	/* 7-SEGMENT LEDs */
    MUX_VAL(CP(MMC2_DAT5),       (IDIS | PTD | EN  | M4)) /*GPIO_137*/
    MUX_VAL(CP(MMC2_DAT4),       (IDIS | PTD | EN  | M4)) /*GPIO_136*/
    MUX_VAL(CP(DSS_DATA15),      (IDIS | PTD | EN  | M4)) /*GPIO_85*/
    MUX_VAL(CP(MMC2_DAT3),       (IDIS | PTD | EN  | M4)) /*GPIO_135*/
    MUX_VAL(CP(MCBSP1_DX),       (IDIS | PTD | EN  | M4)) /*GPIO_158*/
    MUX_VAL(CP(MMC2_DAT2),       (IDIS | PTD | EN  | M4)) /*GPIO_134*/
    MUX_VAL(CP(MCBSP1_CLKX),     (IDIS | PTD | EN  | M4)) /*GPIO_162*/

    MUX_VAL(CP(MMC2_DAT1),       (IDIS | PTD | EN  | M4)) /*GPIO_133*/
    MUX_VAL(CP(MCBSP_CLKS),      (IDIS | PTD | EN  | M4)) /*GPIO_161*/
    MUX_VAL(CP(MMC2_DAT0),       (IDIS | PTD | EN  | M4)) /*GPIO_132*/
    MUX_VAL(CP(MCBSP1_DR),       (IDIS | PTD | EN  | M4)) /*GPIO_159*/
    MUX_VAL(CP(MMC2_CMD),        (IDIS | PTD | EN  | M4)) /*GPIO_131*/
    MUX_VAL(CP(MCBSP1_CLKR),     (IDIS | PTD | EN  | M4)) /*GPIO_156*/
    MUX_VAL(CP(MMC2_CLK),        (IDIS | PTD | EN  | M4)) /*GPIO_130*/

	/* EXTERNAL RESET */
    MUX_VAL(CP(DSS_DATA20),      (IDIS | PTD | EN  | M4)) /*GPIO_90*/

    /* misc */
    MUX_VAL(CP(DSS_DATA8),       (IDIS | PTD | EN  | M4)) /*GPIO_78*/
    MUX_VAL(CP(DSS_DATA9),       (IDIS | PTD | EN  | M4)) /*GPIO_79*/

}

Then rebuild u-boot. (That’s the separate story…)

Alternate Kernel Configuration

Here are the kernel file changes made to support use of UART1 on J4 and J5 connectors of the Rev C2 BeagleBoard.  This is based on pp. 817 and 899 of OMAP3 SCM (which just happens to use UART1 as an example of reconfiguring the pin mux settings) and this reference at HY Research.

File arch/arm/mach-omap2/board-omap3beagle.c:

Added function:

static void __init beagle_uart1_init(void)
{
    omap_cfg_reg(AG22_3430_UART1_CTS_UP);
    omap_cfg_reg(AH22_3430_UART1_RTS);
    omap_cfg_reg(F28_3430_UART1_RX_DOWN);
    omap_cfg_reg(E26_3430_UART1_TX);
}

At end of the function

static void __init omap3_beagle_init(void)

comment out the line:

/*beagle_display_init();*/

since we are remapping some of the DSS data lines to use the UART instead, then add the line:

beagle_uart1_init();

File arch/arm/plat-omap/include/mach/mux.h:

Additions to enum omap34xx_index shown in bold:

    /*  UART1 for BeagleBoard on J4/J5
     */
	AG22_3430_UART1_CTS_UP,
	AH22_3430_UART1_RTS,
	E26_3430_UART1_TX,
	F28_3430_UART1_RX_DOWN
}

File arch/arm/mach-omap2/mux.c:

Additions to the end of static struct pin_config __initdata_or_module omap34xx_pins[] shown in bold:

MUX_CFG_34XX("AE5_34XX_GPIO143", 0x172,
		OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)

/* UART1 for BeagleBoard on J4/J5
 */
MUX_CFG_34XX("AG22_3430_UART1_CTS_UP", 0x0DC,
		OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLUP)
MUX_CFG_34XX("AH22_3430_UART1_RTS", 0x0DE,
		OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_OUTPUT)
MUX_CFG_34XX("E26_3430_UART1_TX", 0x0E8,
		OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_OUTPUT)
MUX_CFG_34XX("F28_3430_UART1_RX_DOWN", 0x0EA,
		OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
};

Then rebuild the kernel (???)  To do this I need to understand where to apply the above changes.

(Turns out kernel mods are more complicated and everything I need can be done with simpler modifications to U-Boot.)