WARP Project Forums - Wireless Open-Access Research Platform

You are not logged in.

#1 2016-May-19 08:09:45

Musty
Member
Registered: 2015-Dec-15
Posts: 4

Implementing TDMA using nomac RefDes_v1.5.1

Hi,

I'm new in the WARP world and I'm trying to implement a simple TDMA mac using nomac RefDes_v1.5.1.

As far as I understood: In nomac the mac_hw  is configured to ignore carrier sensing and nav and pass every Tx packet from user_code through the state machine A to TX PHY.

Code:

// Write the PHY premable 
...
// Set the MAC HW control parameters
....
// Set Tx Gains
...
// Make sure Tx PHY isn't active
while (wlan_mac_get_status() & WLAN_MAC_STATUS_MASK_TX_PHY_ACTIVE) {}

//Starts the MAC hardware's, state machine A
wlan_mac_tx_ctrl_A_start(1);
wlan_mac_tx_ctrl_A_start(0);
do{
.... // Wait for the PHY Tx to finish
} while (mac_hw_status & WLAN_MAC_STATUS_MASK_TX_A_PENDING);

My questions:

1)Since in my protocol after every packet transmission further processing and timing critical event should be handled,  I want to avoid blocking cpu low at the 2nd loop  do-while and do this check just before the next transmission started. So I thought to do this in the first while loop together with the check after TX_PHY_ACTIVE and set a time threshold for that. Would the following check be enough to ensure that TX PHY is ready to process the next packet?

Code:

while ( wlan_mac_get_status() !=  WLAN_MAC_STATUS_MASK_TX_A_DONE ) {}

2) I'm trying also to use wlan_tx_start() for immediate transmission and workaround mac_hw. It didn't work for me. Do I missing something in my code? and how to set Tx Gains and antenna mask in this case? How to check the Tx PHY state before calling wlan_tx_start()?

Code:

u8 TX_BUF=1;
mac_header_80211_ACK* ack_header=(void*)(TX_PKT_BUF_TO_ADDR(TX_BUF) + PHY_TX_PKT_BUF_MPDU_OFFSET);
tx_frame_info_t   * tx_frame_info       = (tx_frame_info_t*) (TX_PKT_BUF_TO_ADDR(TX_BUF));
  
// tx_frame_info->params.phy.antenna_mode=TX_ANTMODE_SISO_ANTA;  !!
// tx_frame_info->params.phy.power=0; !!
tx_frame_info->params.phy.mcs=0;
tx_frame_info->params.phy.phy_mode=PHY_MODE_NONHT;
tx_frame_info->length=sizeof(mac_header_80211_ACK)+WLAN_PHY_FCS_NBYTES;

write_phy_preamble(TX_BUF, tx_frame_info->params.phy.phy_mode, tx_frame_info->params.phy.mcs, tx_frame_info->length);
wlan_tx_buffer_sel(TX_BUF);
wlan_tx_start();

Many thanks in advance

BR
musty

Last edited by Musty (2016-May-19 08:47:04)

Offline

 

#2 2016-May-19 10:00:41

chunter
Administrator
From: Mango Communications
Registered: 2006-Aug-24
Posts: 1212

Re: Implementing TDMA using nomac RefDes_v1.5.1

Musty wrote:

1)Since in my protocol after every packet transmission further processing and timing critical event should be handled,  I want to avoid blocking cpu low at the 2nd loop  do-while and do this check just before the next transmission started. So I thought to do this in the first while loop together with the check after TX_PHY_ACTIVE and set a time threshold for that. Would the following check be enough to ensure that TX PHY is ready to process the next packet?

Code:

while ( wlan_mac_get_status() !=  WLAN_MAC_STATUS_MASK_TX_A_DONE ) {}

Just to make sure I am understanding correctly, you'd like to be able to quit the frame_transmit() context earlier than the DONE event so that you can do some additional processing?

I think there would be some subtle and hard-to-debug effects of doing that. The MAC Low Framework assumes that, after frame_transmit() is called, the Tx state machine is done. Two issues jump to my mind if you break that assumption:

1. Log entries in wlan_exp will be corrupted since NOMAC would not have filled in low_tx_details TX START timestamps. Furthermore, the calculation of the total time the MPDU spent in the Tx state machine will be invalid. These are pretty minor if you don't care about logs. Also, technically, waiting for the done event before filling in low_tx_details timestamps is overly conservative. It's safe to read those out once (mac_hw_status & WLAN_MAC_STATUS_MASK_TX_PHY_ACTIVE) is true.
2. A more serious concern is that the MAC Low Framework will send a IPC message to CPU_HIGH indicating that the transmission is done and is ready to be processed. This introduces a race condition. CPU_HIGH will recycle that packet buffer and, if there is a new packet to send, will overwrite the contents of that packet buffer with a new transmission. Since you haven't guaranteed that the transmission has actually completed, it's possible that CPU_HIGH will overwrite bytes that the PHY has not yet turned into a waveform. This will corrupt your transmission.

It's safest if you could continue to honor the contract with the MAC Low Framework that frame_transmit() only exits once the DONE is complete. Is it possible for you to do your extra processing from within the frame_transmit() context? There is a bubble in the pipeline where code isn't doing much while (mac_hw_status & WLAN_MAC_STATUS_MASK_TX_A_PENDING) is true.



Musty wrote:

2) I'm trying also to use wlan_tx_start() for immediate transmission and workaround mac_hw. It didn't work for me. Do I missing something in my code? and how to set Tx Gains and antenna mask in this case? How to check the Tx PHY state before calling wlan_tx_start()?

Code:

u8 TX_BUF=1;
mac_header_80211_ACK* ack_header=(void*)(TX_PKT_BUF_TO_ADDR(TX_BUF) + PHY_TX_PKT_BUF_MPDU_OFFSET);
tx_frame_info_t   * tx_frame_info       = (tx_frame_info_t*) (TX_PKT_BUF_TO_ADDR(TX_BUF));
  
// tx_frame_info->params.phy.antenna_mode=TX_ANTMODE_SISO_ANTA;  !!
// tx_frame_info->params.phy.power=0; !!
tx_frame_info->params.phy.mcs=0;
tx_frame_info->params.phy.phy_mode=PHY_MODE_NONHT;
tx_frame_info->length=sizeof(mac_header_80211_ACK)+WLAN_PHY_FCS_NBYTES;

write_phy_preamble(TX_BUF, tx_frame_info->params.phy.phy_mode, tx_frame_info->params.phy.mcs, tx_frame_info->length);
wlan_tx_buffer_sel(TX_BUF);
wlan_tx_start();

Bypassing the MAC hardware core is dangerous and something we haven't really tested in depth. It's much better to continue to use it, but just leave all of the deferral options disabled like NOMAC does. I don't think you'd save any time directly accessing the PHY anyway.

Offline

 

#3 2016-May-20 08:03:52

Musty
Member
Registered: 2015-Dec-15
Posts: 4

Re: Implementing TDMA using nomac RefDes_v1.5.1

thanks for the quick response and good explanation,

Another question: what is the difference between

WLAN_MAC_STATUS_MASK_TX_A_DONE       
WLAN_MAC_STATUS_MASK_TX_A_PENDING   
WLAN_MAC_STATUS_MASK_TX_PHY_ACTIVE

and

WLAN_MAC_TXCTRL_STATUS_MASK_TX_A_DONE
WLAN_MAC_TXCTRL_STATUS_MASK_TX_A_PENDING

I guess the TXCTRL status is a state of the TX PHY within/during the WLAN_MAC_STATUS_MASK_TX_PHY_ACTIVE.


BR
Musty

Offline

 

#4 2016-May-20 09:34:42

murphpo
Administrator
From: Mango Communications
Registered: 2006-Jul-03
Posts: 5159

Re: Implementing TDMA using nomac RefDes_v1.5.1

The MAC core (wlan_mac_hw) has two status registers. One (TX_CTRL_STATUS ) is dedicated to the status of the 3 Tx controllers (A, B, C). The other (STATUS) captures status of other blocks.

An important feature of these registers is that each register updates every cycle, capturing all its inputs at the same time. Software can read a status register into a local variable then compare status fields via that local variable. This is much safer than reading the status register many times to compare status bits, since the underlying MAC state can change at any time. For example:

Code:

// Unsafe! Reads status register twice, state might change between reads
x = (wlan_mac_get_status() & WLAN_MAC_STATUS_MASK_TX_PHY_ACTIVE) || (wlan_mac_get_status() & WLAN_MAC_STATUS_MASK_RX_PHY_ACTIVE);

// Safe - reads status register once, compares status fields in local variable
x = wlan_mac_get_status();
y = (x & WLAN_MAC_STATUS_MASK_TX_PHY_ACTIVE) || (x & WLAN_MAC_STATUS_MASK_RX_PHY_ACTIVE);

There are a few places in the MAC code where DONE/PENDING state of the Tx controllers must be compared to other MAC status fields. Thus, the _PENDING and _DONE signals from each Tx controller are captured in both the TX_CTRL_STATUS and STATUS registers. The other Tx controller status fields (STATE, RESULT) are only cpautred in TX_CTRL_STATUS, since these fields are only compared to other Tx controller status fields.

WLAN_MAC_STATUS_MASK_TX_PHY_ACTIVE reflects the instantaneous state of the Tx PHY and will be 1 whenever the Tx PHY is currently transmitting.

Offline

 

#5 2016-May-23 10:15:23

Musty
Member
Registered: 2015-Dec-15
Posts: 4

Re: Implementing TDMA using nomac RefDes_v1.5.1

Thanks..

New questions :D

1) In RefDes_v1.5.0 i can't find where the RX PHY is unblock for further reception. In RefDes_v1.3.0 the function wlan_mac_dcf_hw_unblock_rx_phy() was called for this purpose.
So, how is the RX PHY unblocking mechanism implemented in v1.5.0? Is it still accessible from MAC code?

2) Since system time can't and mac time can be updated during run time by set_mac_time_usec(u64 new_time). Does this function update also the registers used to time stamp pkt transmission/reception? 

Code:

#define XPAR_WLAN_MAC_HW_MEMMAP_TX_START_TIMESTAMP_MSB 0x42000854
#define XPAR_WLAN_MAC_HW_MEMMAP_TX_START_TIMESTAMP_LSB 0x42000858
#define XPAR_WLAN_MAC_HW_MEMMAP_RX_START_TIMESTAMP_MSB 0x4200085C
#define XPAR_WLAN_MAC_HW_MEMMAP_RX_START_TIMESTAMP_LSB 0x42000860
#define XPAR_WLAN_MAC_HW_MEMMAP_TXRX_START_TIMESTAMPS_FRAC 0x42000864

I think it do, just be be sure ;)

3) I'm trying to use the auto reload option by initializing my count down timer as following:

Code:

 
#define XTC_CASCADE_MODE_OPTION		0x00000080UL
#define XTC_ENABLE_ALL_OPTION		0x00000040UL
#define XTC_DOWN_COUNT_OPTION		0x00000020UL
#define XTC_CAPTURE_MODE_OPTION		0x00000010UL
#define XTC_INT_MODE_OPTION		0x00000008UL
#define XTC_AUTO_RELOAD_OPTION		0x00000004UL
#define XTC_EXT_COMPARE_OPTION		0x00000002UL
//........
void wlan_timer_init(){
	int status;
	status = XTmrCtr_Initialize(TmrCtrInstancePtr, TMRCTR_DEVICE_ID);
	if (status != XST_SUCCESS) {
		xil_printf("w3_node_init: Error in XtmrCtr_Initialize (%d)\n", status);

	}
	XTmrCtr_SetOptions(TmrCtrInstancePtr, 0, (XTC_DOWN_COUNT_OPTION | XTC_AUTO_RELOAD_OPTION));
	XTmrCtr_SetOptions(TmrCtrInstancePtr, 1, (XTC_DOWN_COUNT_OPTION | XTC_AUTO_RELOAD_OPTION));
	timer_callback = (function_ptr_t)wlan_null_callback;
}
// Set timer callback
wlan_mac_low_set_timer_callback(		(void*)callback_timer);

Somehow the callback function is called only ones. I have checked the option with XTmrCtr_GetOptions(), and get 24 as return value, which mean that both options DOWN_COUNT and AUTO_RELOAD are set.
So, how to set a certain timer to count down and auto reload ?

Thank you for your support!

BR
Musty

Offline

 

#6 2016-May-23 10:48:25

murphpo
Administrator
From: Mango Communications
Registered: 2006-Jul-03
Posts: 5159

Re: Implementing TDMA using nomac RefDes_v1.5.1

1) In RefDes_v1.5.0 i can't find where the RX PHY is unblock for further reception. In RefDes_v1.3.0 the function wlan_mac_dcf_hw_unblock_rx_phy() was called for this purpose.
So, how is the RX PHY unblocking mechanism implemented in v1.5.0? Is it still accessible from MAC code?

We re-designed the MAC/Rx PHY interaction in v1.5. The v1.5 MAC core implements a latch named RX_STARTED. This latch asserts every time the Rx PHY begins a new reception. When the RX_STARTED latch is asserted the Rx PHY will not begin a new reception. This implements the same "blocking" behavior of previous releases, allowing MAC software to process a reception before the Rx PHY begins a new reception. However, unlike previous releases, the v1.5 MAC software can clear this latch any time (during Rx, after Rx). In the reference code the RX_STARTED latch is cleared in the low framework's wlan_mac_low_poll_frame_rx() after the DCF frame_receive() callback returns.

2) Since system time can't and mac time can be updated during run time by set_mac_time_usec(u64 new_time). Does this function update also the registers used to time stamp pkt transmission/reception?

The R/TX_START_TIMESAMP registers are read-only. The MAC core captures the current MAC Time value at every TX_START and RX_START event and saves the captured value to those registers. The current value of the R/TX_START_TIMESTAMP registers (i.e. the timestamps of the most recent Tx/Rx event) do not change when the MAC Time changes. If the MAC Time changes (i.e. beacon Rx, node reset), the next TX_START / RX_START event will capture a timestamp using the new MAC Time timebase.

Offline

 

#7 2016-May-23 10:57:51

chunter
Administrator
From: Mango Communications
Registered: 2006-Aug-24
Posts: 1212

Re: Implementing TDMA using nomac RefDes_v1.5.1

Musty wrote:

Thanks..
3) I'm trying to use the auto reload option by initializing my count down timer as following:

Code:

 
#define XTC_CASCADE_MODE_OPTION		0x00000080UL
#define XTC_ENABLE_ALL_OPTION		0x00000040UL
#define XTC_DOWN_COUNT_OPTION		0x00000020UL
#define XTC_CAPTURE_MODE_OPTION		0x00000010UL
#define XTC_INT_MODE_OPTION		0x00000008UL
#define XTC_AUTO_RELOAD_OPTION		0x00000004UL
#define XTC_EXT_COMPARE_OPTION		0x00000002UL
//........
void wlan_timer_init(){
	int status;
	status = XTmrCtr_Initialize(TmrCtrInstancePtr, TMRCTR_DEVICE_ID);
	if (status != XST_SUCCESS) {
		xil_printf("w3_node_init: Error in XtmrCtr_Initialize (%d)\n", status);

	}
	XTmrCtr_SetOptions(TmrCtrInstancePtr, 0, (XTC_DOWN_COUNT_OPTION | XTC_AUTO_RELOAD_OPTION));
	XTmrCtr_SetOptions(TmrCtrInstancePtr, 1, (XTC_DOWN_COUNT_OPTION | XTC_AUTO_RELOAD_OPTION));
	timer_callback = (function_ptr_t)wlan_null_callback;
}
// Set timer callback
wlan_mac_low_set_timer_callback(		(void*)callback_timer);

Somehow the callback function is called only ones. I have checked the option with XTmrCtr_GetOptions(), and get 24 as return value, which mean that both options DOWN_COUNT and AUTO_RELOAD are set.
So, how to set a certain timer to count down and auto reload ?

We use the auto reload option in the scheduler in CPU_HIGH and it seems to work well. However, that scenario is a different than yours since it is interrupt-based. I don't have any experience using the Xilinx timer in a polled system like in CPU_LOW.

Do you need to use the hardware timer for your design? By polling get_system_time_usec() in the while() loop of main(), you can perform operations at any time you wish. So, for example, you can periodically call a function whenever the system time exceeds a certain value. This would be nearly equivalent to using a hardware timer and is much easier for a simple polling architecture like CPU_LOW.

Offline

 

Board footer