You are not logged in.
Hi WARP Team,
we're currently in the process of developing a TDMA-style MAC and recently ported the system over to the Reference Design 1.5.1 hoping that we could remove the workaround for the blocking RX-PHY in v 1.4.
Now in 1.5.1, we observed two behaviours we cannot quite explain:
1. Even if we configure the MAC-Core using
REG_SET_BITS(WLAN_MAC_REG_CONTROL, (WLAN_MAC_CTRL_MASK_CCA_IGNORE_PHY_CS | WLAN_MAC_CTRL_MASK_CCA_IGNORE_NAV | WLAN_MAC_CTRL_MASK_DISABLE_NAV));
calls to wlan_mac_get_status still indicate WLAN_MAC_STATUS_MASK_CCA_BUSY unless we add
wlan_phy_rx_set_cca_thresh(0xFFFF);
Is this behaviour intended?
2. Due to their timing behaviour, we want to fully disable DSSS receptions.
We tried doing so with two different approaches:
First, we utilized the function
wlan_mac_low_DSSS_rx_disable();
but were still seeing DSSS receptions in wlan_mac_low_poll_frame_rx, even though we are sure that the DSSS is never enabled again afterwards, and to be sure we even called
wlan_mac_low_DSSS_rx_disable();
everytime a new DSSS packet was received, to make sure it didn't get enabled again. DSSS Packets were however still received.
As a second method, we disabled it in wlan_phy_init as indicated in its comments:
void wlan_phy_init() { //-snip- // Configure the DSSS auto-correlation packet detector // wlan_phy_pktDet_autoCorr_dsss_cfg(corr_thresh, energy_thresh, timeout_ones, timeout_count) // // To effectively disable DSSS detection with high thresholds, substitute with the following line: wlan_phy_rx_pktDet_autoCorr_dsss_cfg(0xFF, 0x3FF, 30, 40); //wlan_phy_rx_pktDet_autoCorr_dsss_cfg(0x60, 400, 30, 40); //-snip- }
but are still seeing DSSS receptions in wlan_mac_low_poll_frame_rx. Is there anything we're missing?
Greetings
Offline
Regarding the DSSS behavior, I wasn't able to reproduce the issue with the v1.5.1 release. I added the following line:
xil_printf("wlan_mac_get_rx_phy_sel() = %08x\n", wlan_mac_get_rx_phy_sel());
to line 562. With no other changes to an otherwise idle AP+DCF design, there are a bunch of prints of "0x00000000" for DSSS and "0x1000000" for OFDM from surrounding Wi-Fi traffic.
Next, I added a call to wlan_mac_low_DSSS_rx_disable() at the end of wlan_mac_low_init() on line 243. After this call, I only ever see prints of "0x10000000" for OFDM.
1) Where are you calling wlan_mac_low_DSSS_rx_disable()? You mentioned that you tried calling it after every DSSS reception -- where in the code did this call take place?
2) Where in wlan_mac_low_poll_frame_rx() are you seeing a DSSS reception? Are you checking the status bit after the PHY Rx has started? (i.e. mac_hw_status & WLAN_MAC_STATUS_MASK_RX_PHY_STARTED)
Offline
chunter wrote:
1) Where are you calling wlan_mac_low_DSSS_rx_disable()? You mentioned that you tried calling it after every DSSS reception -- where in the code did this call take place?
First, we called it directly before our protocol starts its main loop (equivalent to after http://warpproject.org/trac/browser/Ref … =5490#L112 )
When we still saw DSS receptions, we added it to the if branch here to make sure it gets called + not overwritten http://warpproject.org/trac/browser/Ref … =5490#L564
chunter wrote:
2) Where in wlan_mac_low_poll_frame_rx() are you seeing a DSSS reception? Are you checking the status bit after the PHY Rx has started? (i.e. mac_hw_status & WLAN_MAC_STATUS_MASK_RX_PHY_STARTED)
We added a printout to the if branch at http://warpproject.org/trac/browser/Ref … =5490#L564 which we expected to not get triggered after disabling DSSS, but wlan_mac_get_rx_phy_sel() == WLAN_MAC_PHY_RX_PHY_HDR_PHY_SEL_DSSS still triggered.
To add a bit more background to our current setup: We're in the process of evaluating the protocol at high interference, and are running an iperf data stream over consumer wlan hardware (802.11a on 5GHz channel 3, bandwidth 40MHz with raw bitrates of up to 130Mbit/s) on the same channel as the protocol which runs at 20MHz on channel 3.
Last edited by Edlmann (2016-May-17 15:06:05)
Offline
I've been reviewing the MAC and Rx PHY logic to see how it might behave this way when the DSSS Rx pipeline is in reset; I haven't found anything.
Can you try an experiment to rule out your other design customizations? Start with the v1.5.1 design, then modify it to include a print in the WLAN_MAC_PHY_RX_PHY_HDR_PHY_SEL_DSSS clause and to set WLAN_DEFAULT_CHANNEL to your 5GHz channel. Does this design ever enter the PHY_SEL_DSSS clause? If so, try adding wlan_mac_low_DSSS_rx_disable() at the end of wlan_mac_low_init() and testing again.
Offline
After modifying the system to never transmit anything and simplyfing the main loop to
wlan_mac_low_DSSS_rx_disable(); while(1) { wlan_mac_low_poll_frame_rx(); wlan_mac_low_poll_ipc_rx(); //We utilize custom IPC messages to reconfigure the boards at runtime (channel, modulation etc, necessitating this callback aswell) }
with receptions beeing only handled as outlined below, except for any further processing and a print included
// Check whether this is an OFDM or DSSS Rx if(wlan_mac_get_rx_phy_sel() == WLAN_MAC_PHY_RX_PHY_HDR_PHY_SEL_DSSS) { xil_printf("DSSSRec\r\n"); // DSSS Rx - PHY Rx length is already valid, other params unused for DSSS phy_details.phy_mode = PHY_MODE_DSSS; phy_details.N_DBPS = 0; // Strip off extra pre-MAC-header bytes used in DSSS frames; this adjustment allows the next // function to treat OFDM and DSSS payloads the same phy_details.length = wlan_mac_get_rx_phy_length() - 5; phy_details.mcs = 0; // Call the user callback to handle this Rx, capture return value return_status |= POLL_MAC_STATUS_RECEIVED_PKT; return_status |= frame_rx_callback(rx_pkt_buf, &phy_details); } else {
it never gets triggered. Only once transmissions are enabled the printout is triggered. It seems to be some interaction between transmissions / receptions causing this behaviour.
I'll try to compile the changes we made compared to the nomac system:
Initialization:
void wlan_phy_init() { // Configure the DSSS Rx pipeline // wlan_phy_DSSS_rx_config(code_corr, despread_dly, sfd_timeout) //wlan_phy_DSSS_rx_config(0x30, 5, 140); wlan_phy_DSSS_rx_config(0xFFFF, 5, 1); //Original values show the same behaviour // Configure the DSSS auto-correlation packet detector // wlan_phy_pktDet_autoCorr_dsss_cfg(corr_thresh, energy_thresh, timeout_ones, timeout_count) // // To effectively disable DSSS detection with high thresholds, substitute with the following line: wlan_phy_rx_pktDet_autoCorr_dsss_cfg(0xFF, 0x3FF, 30, 40); //wlan_phy_rx_pktDet_autoCorr_dsss_cfg(0x60, 400, 30, 40); } void main() { wlan_mac_low_init(); // - snip - wlan_mac_low_init_finish(); REG_SET_BITS(WLAN_MAC_REG_CONTROL, (WLAN_MAC_CTRL_MASK_CCA_IGNORE_PHY_CS | WLAN_MAC_CTRL_MASK_CCA_IGNORE_NAV)); wlan_phy_rx_set_cca_thresh(0xFFFF); set_phy_samp_rate(PHY_20M); REG_SET_BITS(WLAN_MAC_REG_CONTROL, (WLAN_MAC_CTRL_MASK_DISABLE_NAV | WLAN_MAC_CTRL_MASK_BLOCK_RX_ON_TX )); wlan_mac_low_DSSS_rx_disable(); // - snip - main loop }
Reception:
u32 frame_receive(u8 rx_pkt_buf, phy_rx_details_t* phy_details){ rx_frame_info_t* mpdu_info; //u32 mac_hw_status; //u8 ctrl_tx_gain; u8* pkt_buf_addr; pkt_buf_addr = (void *)RX_PKT_BUF_TO_ADDR(rx_pkt_buf); mpdu_info = (rx_frame_info_t*)pkt_buf_addr; // - snip - collect metadata about reception if (phy_details->length < NUM_HEADER_BYTES || phy_details->length > MAX_PACKET_LENGTH || (phy_details->mcs != WLAN_MAC_MCS_12M) || phy_details->phy_mode == PHY_MODE_DSSS) { //This block was testing for clearing an rx faster, but is disabled to track down the current issue /*wlan_mac_hw_clear_rx_started(); REG_SET_BITS(WLAN_MAC_REG_CONTROL, WLAN_MAC_CTRL_MASK_RESET_PHY_ACTIVE_LATCHES); REG_CLEAR_BITS(WLAN_MAC_REG_CONTROL, WLAN_MAC_CTRL_MASK_RESET_PHY_ACTIVE_LATCHES);*/ //Early return for packets that cannot be from the protocol return -1; } mpdu_info->state = CALLBACK_ERROR; mpdu_info->state = wlan_mac_hw_rx_finish(); // - snip - process received packet if mpdu_info->state == 1 }
The logic inside wlan_mac_low_poll_frame_rx is unchanged except for the added printout.
Transmission:
int frame_transmit(u8 pkt_buf, u8 mcs, u16 length) { //This function manages the MAC5_DCF_HW core. void* pkt_buf_addr = (void *)TX_PKT_BUF_TO_ADDR(pkt_buf); tx_frame_info_t* mpdu_info = (tx_frame_info_t*) (pkt_buf_addr); int curr_tx_pow; u32 mac_hw_status; u32 mac_tx_ctrl_status; s8 retVal = CALLBACK_ERROR; //Write the SIGNAL field (interpreted by the PHY during Tx waveform generation) write_phy_preamble(pkt_buf, PHY_MODE_NONHT, mcs, length); unsigned char mpdu_tx_ant_mask = 0x1; mpdu_info->num_tx_attempts = 1; // Update tx_frame_info with current PHY sampling rate mpdu_info->phy_samp_rate = (u8)wlan_mac_low_get_phy_samp_rate(); //curr_tx_pow = wlan_mac_low_dbm_to_gain_target(mpdu_info->params.phy.power); curr_tx_pow = wlan_mac_low_get_current_ctrl_tx_pow(); //wlan_mac_tx_ctrl_A_params(pktBuf, antMask, preTx_backoff_slots, preWait_postRxTimer1, preWait_postTxTimer1, postWait_postTxTimer2) wlan_mac_tx_ctrl_A_params(pkt_buf, mpdu_tx_ant_mask, 0, 0, 0, 0, PHY_MODE_NONHT); //Set Tx Gains wlan_mac_tx_ctrl_A_gains(curr_tx_pow, curr_tx_pow, curr_tx_pow, curr_tx_pow); //Before we mess with any PHY state, we need to make sure it isn't actively if (wlan_mac_get_status() & WLAN_MAC_STATUS_MASK_TX_PHY_ACTIVE) { xil_printf("TX active still\r\n"); // Never occurs goto frame_transmit_end; } //Submit the MPDU for transmission - this starts the MAC hardware's MPDU Tx state machine wlan_mac_tx_ctrl_A_start(1); wlan_mac_tx_ctrl_A_start(0); // Wait for the PHY Tx to finish do{ // Get the MAC HW status mac_hw_status = wlan_mac_get_status(); mac_tx_ctrl_status = wlan_mac_get_tx_ctrl_status(); // If the MAC HW is done, fill in the remaining Tx low details and return if (mac_tx_ctrl_status & WLAN_MAC_TXCTRL_STATUS_MASK_TX_A_DONE) { // Set return value based on Tx A result switch (mac_tx_ctrl_status & WLAN_MAC_TXCTRL_STATUS_MASK_TX_A_RESULT) { case WLAN_MAC_TXCTRL_STATUS_TX_A_RESULT_NONE: case WLAN_MAC_TXCTRL_STATUS_TX_A_RESULT_RX_STARTED: retVal = CALLBACK_OK; goto frame_transmit_end; break; default: retVal = CALLBACK_ERROR; goto frame_transmit_end; break; } } } while (mac_hw_status & WLAN_MAC_STATUS_MASK_TX_A_PENDING); frame_transmit_end:; if (retVal == CALLBACK_ERROR) { // wlan_mac_reset_tx_ctrl_a(1); // wlan_mac_reset_tx_ctrl_a(0); } if (retVal == CALLBACK_ERROR) { return TX_MPDU_RESULT_FAILURE; } else { return TX_MPDU_RESULT_SUCCESS; } }
Offline
Does your custom code ever start a Tx while the Rx PHY is currently receiving a frame? That's definitely a combination of states we don't use. It's possible that would expose some interaction in the Rx PHY -> MAC state. I'll dig deeper if this is a possibility in your code.
Offline
Yes, that can happen. As soon as we enter the rx-callback with a packet we can discard based on the PLCP, the frame_receive callback returns early. In this case, wlan_mac_hw_clear_rx_started(); is still beeing called however. But if the protocol is currently busy processing an event (timing based / reaction to a past reception) it might generate a new transmission, calling frame_transmit directly. We removed the check for rx-activity inside the frame_transmit callback, since we need this function be fully fire and forget, with as little delay before a transmission is started as possible. A transmission should always take precedence over a reception. Is there a better way to achieve this without unintended side effects?
Offline
I have two ideas-
-Check the 'WLAN_MAC_PHY_RX_PHY_HDR_READY' bit in the code block that detects the bogus DSSS Rx - it should be 0 for a DSSS Rx
-De-assert the 'WLAN_MAC_CTRL_MASK_BLOCK_RX_ON_TX' option in wlan_mac_hw_init().
The wlan_mac_hw register 'PHY_RX_PARAMS' updates twice per OFDM reception- once at RX_START, again after the 9th byte (HT-SIG) is decoded. On the second update the 'WLAN_MAC_PHY_RX_PHY_HDR_READY' bit will be asserted. For DSSS receptions this register only updates at RX_START and the 'WLAN_MAC_PHY_RX_PHY_HDR_READY' bit will never be asserted (since the OFDM pipeline isn't even running). The 'PHY_RX_PARAMS' register also captures the 'PHY_SEL' bit (0=DSSS, 1=OFDM). This bit is driven by a latch that asserts on an OFDM RX_START and stays asserted until OFDM RX_END. Normally RX_END occurs when the last byte is decoded. However if a Tx starts during an Rx, the MAC core asserts the Rx PHY's RX_RESET input. This mimics an RX_END (via the 'RX_RESET_WHILE_ACTIVE' goto) and clears the PHY_SEL latch. There is a narrow window where the Rx PHY could be decoding the HT-SIG (about to assert RX_PHY_HDR_READY) when the RX_RESET occurs. This would clear the PHY_SEL latch, leading to a 'PHY_RX_PARAMS' where PHY_SEL=0 ("DSSS", but not really) and RX_PHY_HDR_READY=1 (OFDM decoded the PHY header).
Offline
The WLAN_MAC_PHY_RX_PHY_HDR_READY bit is indeed asserted for those DSSS receptions. (Full phy_hdr_params are switching between 0x9040085, 0x9000085, 0xA870085 and 0xA000085 at the beginning of the DSSS-Clause).
De-asserting WLAN_MAC_CTRL_MASK_BLOCK_RX_ON_TX does indeed get rid of the unwanted DSSS signals.
Are there any side-effects that we would need to be aware of with this configuration? With the new config I noticed that the RX is now sometimes active directly after (or during) a transmission. Due to the TDMA nature of our MAC, this is most likely a packet received from an interfering system, and should not be further processed. How would we go about discarding these receptions directly after transmission? Utilizing wlan_mac_hw_clear_rx_started(); seems to lead to some unintended side-effects with invalid packets being marked as valid for further processing (If this is not as expected, i can try to track it down further. Just did some initial testing).
Thanks a lot already for your help murphpo + chunter
Offline
The WLAN_MAC_PHY_RX_PHY_HDR_READY bit is indeed asserted for those DSSS receptions. (Full phy_hdr_params are switching between 0x9040085, 0x9000085, 0xA870085 and 0xA000085 at the beginning of the DSSS-Clause).
De-asserting WLAN_MAC_CTRL_MASK_BLOCK_RX_ON_TX does indeed get rid of the unwanted DSSS signals.
Great- I think that means we've narrowed down the underlying issue.
Decoding those PHY_HDR_PARAMS values (bit masks in wlan_mac_low.h):
0x09040085 Length: 0x85 MCS: 4 Unsupported: False PHY Mode: 1 (NONHT) Header Ready: True PHY Sel: 0 (DSSS) 0x09000085 Length: 0x85 MCS: 0 Unsupported: False PHY Mode: 1 (NONHT) Header Ready: True PHY Sel: 0 (DSSS) 0x0A870085 Length: 0x85 MCS: 7 Unsupported: True PHY Mode: 2 (HTMF) Header Ready: True PHY Sel: 0 (DSSS) 0x0A000085 Length: 0x85 MCS: 0 Unsupported: False PHY Mode: 2 (HTMF) Header Ready: True PHY Sel: 0 (DSSS)
Those are all consistent with OFDM receptions that were interrupted by an Rx PHY reset between RX_START and PHY_HDR_READY. The reset signal clears the latch in the "MAC I/O" block that selects between DSSS and OFDM parameters. When the PHY asserts the PHY_HDR_READY signal the multiplexed params (including length and PHY_SEL) have reverted to the DSSS defaults. These defaults (length = 133 = 0x85, PHY_SEL = DSSS = 0) are captured in the MAC core's PHY_HDR_PARAMS register, giving the bogus-looking combinations of params above.
I would suggest leaving WLAN_MAC_CTRL_MASK_BLOCK_RX_ON_TX enabled. This should simplify detecting the edge cases resulting from an Rx that is interrupted by Tx.
I think the best way to handle this edge case is to modify wlan_mac_low_poll_frame_rx() to handle this case explicitly, looking for the combination of params that indicate an early Rx PHY reset:
// Check if PHY has started a new reception if(mac_hw_status & WLAN_MAC_STATUS_MASK_RX_PHY_STARTED) { // First check if Rx PHY was reset before RX_PHY_HDR_READY asserted. In this case // the PHY_HDR_PARAMS cannot be trusted. The RX_STARTED latch should be cleared, // allowing the Rx PHY to start over with the next reception if((wlan_mac_get_rx_phy_sel() == WLAN_MAC_PHY_RX_PHY_HDR_PHY_SEL_DSSS) && (phy_hdr_params & WLAN_MAC_PHY_RX_PHY_HDR_READY)) { // Set no return flags (nothing was received); fall through to clear RX_STARTED return_status = 0; } else if(wlan_mac_get_rx_phy_sel() == WLAN_MAC_PHY_RX_PHY_HDR_PHY_SEL_DSSS) { // DSSS Rx - PHY Rx length is already valid, other params unused for DSSS ...
Offline