Generating Barker code using HW

I’m using ZedBoard with FMCOMMS3 and trying to generate a 13 symbol barker code [+1, +1, +1, +1, +1, -1, -1, +1, +1, -1, +1, -1, +1] at the transmitter side before sending my actual data. I’m trying to do so using SW, but I’m still not successful and I have some concerns about timing as my application is highly time dependent (I’m posting a question there). In my software approach, I’m trying to modify the sine LUT in the dac_core.c file. My question is, how can I generate a Barker code sequence and send it using the FMCOMMS2 base design?
Another point to mention, during my search I found out that generating BPSK symbols is somewhat similar to generating a barker code (180 degrees phase shift between 0 and 1), however I didn’t find much info about how to implement it. If BPSK is easier than implementing Barker code in the base design, how can I implement it?

  • A barker code is unmodulated data technically, and in a communication system you will want to modulate (and match filter) the barker sequence. Along with payload information.

    Can you provide detail on how you want to control this generation of the barker sequence? Doing thing in FPGA fabric is more deterministic, but this can be done through software easily enough.

    -Travis

  • Travis,

    Basically, what I want to do is to generate 1 period of a sine wave without phase shift for the 1 symbol of the Barker code and generate a single period with 180 degrees shift for the -1 symbol. This image is a simple example of what I want:

    I tried to modify the LUT in the dac_core.c file as seen in the attached txt file

    3240.modified_lut.txt
    const uint16_t sine_lut[256] = {
    0x000, 0x064, 0x0C8, 0x12C, 0x18F, 0x1F1, 0x252, 0x2B1,
    0x30F, 0x36B, 0x3C5, 0x41C, 0x471, 0x4C3, 0x512, 0x55F,
    0x5A7, 0x5ED, 0x62E, 0x66C, 0x6A6, 0x6DC, 0x70D, 0x73A,
    0x763, 0x787, 0x7A7, 0x7C2, 0x7D8, 0x7E9, 0x7F5, 0x7FD,
    0x7FF, 0x7FD, 0x7F5, 0x7E9, 0x7D8, 0x7C2, 0x7A7, 0x787,
    0x763, 0x73A, 0x70D, 0x6DC, 0x6A6, 0x66C, 0x62E, 0x5ED,
    0x5A7, 0x55F, 0x512, 0x4C3, 0x471, 0x41C, 0x3C5, 0x36B,
    0x30F, 0x2B1, 0x252, 0x1F1, 0x18F, 0x12C, 0x0C8, 0x064,
    0x000, 0xF9B, 0xF37, 0xED3, 0xE70, 0xE0E, 0xDAD, 0xD4E,
    0xCF0, 0xC94, 0xC3A, 0xBE3, 0xB8E, 0xB3C, 0xAED, 0xAA0,
    0xA58, 0xA12, 0x9D1, 0x993, 0x959, 0x923, 0x8F2, 0x8C5,
    0x89C, 0x878, 0x858, 0x83D, 0x827, 0x816, 0x80A, 0x802,
    0x800, 0x802, 0x80A, 0x816, 0x827, 0x83D, 0x858, 0x878,
    0x89C, 0x8C5, 0x8F2, 0x923, 0x959, 0x993, 0x9D1, 0xA12,
    0xA58, 0xAA0, 0xAED, 0xB3C, 0xB8E, 0xBE3, 0xC3A, 0xC94,
    0xCF0, 0xD4E, 0xDAD, 0xE0E, 0xE70, 0xED3, 0xF37, 0xF9B,
    0x000, 0xF9B, 0xF37, 0xED3, 0xE70, 0xE0E, 0xDAD, 0xD4E,
    0xCF0, 0xC94, 0xC3A, 0xBE3, 0xB8E, 0xB3C, 0xAED, 0xAA0,
    0xA58, 0xA12, 0x9D1, 0x993, 0x959, 0x923, 0x8F2, 0x8C5,
    0x89C, 0x878, 0x858, 0x83D, 0x827, 0x816, 0x80A, 0x802,
    0x800, 0x802, 0x80A, 0x816, 0x827, 0x83D, 0x858, 0x878,
    0x89C, 0x8C5, 0x8F2, 0x923, 0x959, 0x993, 0x9D1, 0xA12,
    0xA58, 0xAA0, 0xAED, 0xB3C, 0xB8E, 0xBE3, 0xC3A, 0xC94,
    0xCF0, 0xD4E, 0xDAD, 0xE0E, 0xE70, 0xED3, 0xF37, 0xF9B,
    0x000, 0x064, 0x0C8, 0x12C, 0x18F, 0x1F1, 0x252, 0x2B1,
    0x30F, 0x36B, 0x3C5, 0x41C, 0x471, 0x4C3, 0x512, 0x55F,
    0x5A7, 0x5ED, 0x62E, 0x66C, 0x6A6, 0x6DC, 0x70D, 0x73A,
    0x763, 0x787, 0x7A7, 0x7C2, 0x7D8, 0x7E9, 0x7F5, 0x7FD,
    0x7FF, 0x7FD, 0x7F5, 0x7E9, 0x7D8, 0x7C2, 0x7A7, 0x787,
    0x763, 0x73A, 0x70D, 0x6DC, 0x6A6, 0x66C, 0x62E, 0x5ED,
    0x5A7, 0x55F, 0x512, 0x4C3, 0x471, 0x41C, 0x3C5, 0x36B,
    0x30F, 0x2B1, 0x252, 0x1F1, 0x18F, 0x12C, 0x0C8, 0x064
    };

    However, the signal at the receiver side is not even a sine wave as seen in the next screenshot:

    Received signal

    How can I generate a signal similar to the first image?

  • I did some search and found the following post which changes LUT on interrupts:

    https://ez.analog.com/linux-device-drivers/microcontroller-no-os-drivers/f/q-a/85912/ad9361-dac-multiple-lut-synchronisation

    In my program, I defined two sine LUT, one for the +1 part and one for the -1 part. I've tested each one alone and the result at the receiver side is a correct sine wave. I then implemented an interrupt handler to be triggered at end-of-transfer (EOT) like the post I linked. The interrupt handler basically switch between the +1 sine and the -1 sine. Here's the result I currently have as seen at the receiver side:

    The current problem is the discontinuity of each period. It suddenly stops and transmits the other sine LUT. Here's the code I'm implementing. Please note that I'm doing it in the dac_core.c, and I'm calling dac_dma_int_handler() function from main.c:

    // Address in DMA for the +1 and -1 sine waves. Defined at the beginning of dac_core.c
    #define BARKER_POS_BASEADDR		0x0F000000U
    #define BARKER_NEG_BASEADDR		0x0FF00000U
    .
    .
    .
    // LUT of +1 sine (barker_pos) and -1 sine (barker_neg)
     const uint16_t barker_pos[128] = {
    		0x000, 0x064, 0x0C8, 0x12C, 0x18F, 0x1F1, 0x252, 0x2B1,
    		0x30F, 0x36B, 0x3C5, 0x41C, 0x471, 0x4C3, 0x512, 0x55F,
    		0x5A7, 0x5ED, 0x62E, 0x66C, 0x6A6, 0x6DC, 0x70D, 0x73A,
    		0x763, 0x787, 0x7A7, 0x7C2, 0x7D8, 0x7E9, 0x7F5, 0x7FD,
    		0x7FF, 0x7FD, 0x7F5, 0x7E9, 0x7D8, 0x7C2, 0x7A7, 0x787,
    		0x763, 0x73A, 0x70D, 0x6DC, 0x6A6, 0x66C, 0x62E, 0x5ED,
    		0x5A7, 0x55F, 0x512, 0x4C3, 0x471, 0x41C, 0x3C5, 0x36B,
    		0x30F, 0x2B1, 0x252, 0x1F1, 0x18F, 0x12C, 0x0C8, 0x064,
    		0x000, 0xF9B, 0xF37, 0xED3, 0xE70, 0xE0E, 0xDAD, 0xD4E,
    		0xCF0, 0xC94, 0xC3A, 0xBE3, 0xB8E, 0xB3C, 0xAED, 0xAA0,
    		0xA58, 0xA12, 0x9D1, 0x993, 0x959, 0x923, 0x8F2, 0x8C5,
    		0x89C, 0x878, 0x858, 0x83D, 0x827, 0x816, 0x80A, 0x802,
    		0x800, 0x802, 0x80A, 0x816, 0x827, 0x83D, 0x858, 0x878,
    		0x89C, 0x8C5, 0x8F2, 0x923, 0x959, 0x993, 0x9D1, 0xA12,
    		0xA58, 0xAA0, 0xAED, 0xB3C, 0xB8E, 0xBE3, 0xC3A, 0xC94,
    		0xCF0, 0xD4E, 0xDAD, 0xE0E, 0xE70, 0xED3, 0xF37, 0xF9B
    };
    
    const uint16_t barker_neg[128] = {
    0x000, 0xF9B, 0xF37, 0xED3, 0xE70, 0xE0E, 0xDAD, 0xD4E,
    		0xCF0, 0xC94, 0xC3A, 0xBE3, 0xB8E, 0xB3C, 0xAED, 0xAA0,
    		0xA58, 0xA12, 0x9D1, 0x993, 0x959, 0x923, 0x8F2, 0x8C5,
    		0x89C, 0x878, 0x858, 0x83D, 0x827, 0x816, 0x80A, 0x802,
    		0x800, 0x802, 0x80A, 0x816, 0x827, 0x83D, 0x858, 0x878,
    		0x89C, 0x8C5, 0x8F2, 0x923, 0x959, 0x993, 0x9D1, 0xA12,
    		0xA58, 0xAA0, 0xAED, 0xB3C, 0xB8E, 0xBE3, 0xC3A, 0xC94,
    		0xCF0, 0xD4E, 0xDAD, 0xE0E, 0xE70, 0xED3, 0xF37, 0xF9B,
            0x000, 0x064, 0x0C8, 0x12C, 0x18F, 0x1F1, 0x252, 0x2B1,
    		0x30F, 0x36B, 0x3C5, 0x41C, 0x471, 0x4C3, 0x512, 0x55F,
    		0x5A7, 0x5ED, 0x62E, 0x66C, 0x6A6, 0x6DC, 0x70D, 0x73A,
    		0x763, 0x787, 0x7A7, 0x7C2, 0x7D8, 0x7E9, 0x7F5, 0x7FD,
    		0x7FF, 0x7FD, 0x7F5, 0x7E9, 0x7D8, 0x7C2, 0x7A7, 0x787,
    		0x763, 0x73A, 0x70D, 0x6DC, 0x6A6, 0x66C, 0x62E, 0x5ED,
    		0x5A7, 0x55F, 0x512, 0x4C3, 0x471, 0x41C, 0x3C5, 0x36B,
    		0x30F, 0x2B1, 0x252, 0x1F1, 0x18F, 0x12C, 0x0C8, 0x064
    };
    
    char sign = 1; // used to switch between LUTs
    // Function to prepare the data and place it in memory.
    // This is the exact same code taken from dac_core.c lines 277 to 286
    void dma_barker_init()
    {
    	uint32_t tx_count = sizeof(barker_pos)/sizeof(uint16_t);
    	uint32_t index, index_i, index_q, data_i, data_q;
    	for(index = 0; index < tx_count; index += 1)
    	{
    		index_i = index;
    		index_q = index + (tx_count / 4);
    		if(index_q >= tx_count)
    			index_q -= tx_count;
    		data_i = (barker_pos[index_i] << 20);
    		data_q = (barker_pos[index_q] << 4);
    		Xil_Out32(BARKER_POS_BASEADDR + index * 4, data_i | data_q);
    	}
    	for(index = 0; index < tx_count; index += 1)
    	{
    		index_i = index;
    		index_q = index + (tx_count / 4);
    		if(index_q >= tx_count)
    			index_q -= tx_count;
    		data_i = (barker_neg[index_i] << 20);
    		data_q = (barker_neg[index_q] << 4);
    		Xil_Out32(BARKER_NEG_BASEADDR + index * 4, data_i | data_q);
    	}
    	Xil_DCacheFlush();
    }
    void dac_init(struct ad9361_rf_phy *phy, uint8_t data_sel, uint8_t config_dma)
    {
    .
    .
    .
    // Beginning from Xil_DCacheFlush();
            dma_barker_init();
        	Xil_DCacheFlush();
            length = (tx_count * 4); //Only using 1 tx
        
        	dac_dma_write(AXI_DMAC_REG_CTRL, 0);
        	dac_dma_write(AXI_DMAC_REG_CTRL, AXI_DMAC_CTRL_ENABLE);
        	dac_dma_write(AXI_DMAC_REG_IRQ_MASK, AXI_DMAC_IRQ_EOT);
        	dac_dma_write(AXI_DMAC_REG_FLAGS, 0);
        	dac_dma_write(AXI_DMAC_REG_SRC_ADDRESS, BARKER_POS_BASEADDR);
        	dac_dma_write(AXI_DMAC_REG_SRC_STRIDE, 0x0);
        	dac_dma_write(AXI_DMAC_REG_X_LENGTH, length - 1);
        	dac_dma_write(AXI_DMAC_REG_Y_LENGTH, 0x0);
        	dac_dma_write(AXI_DMAC_REG_START_TRANSFER, 0x1);
        }
        // No changes after this point
    }
    .
    .
    .
    // Called from main.c when the interrupt is triggered
    void dac_dma_int_handler()
    {
    	  uint32_t reg_val = 0;
    	  dac_dma_read(AXI_DMAC_REG_IRQ_PENDING, &reg_val);
          dac_dma_write(AXI_DMAC_REG_IRQ_PENDING, reg_val);
          if(sign == 1)
        	  dac_dma_write(AXI_DMAC_REG_SRC_ADDRESS, BARKER_POS_BASEADDR);
          else
        	  dac_dma_write(AXI_DMAC_REG_SRC_ADDRESS, BARKER_NEG_BASEADDR);
          sign *=-1;
          dac_dma_write(AXI_DMAC_REG_START_TRANSFER, 0x1);
    }