国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

普冉PY32系列(八) GPIO模擬和硬件SPI方式驅(qū)動(dòng)無(wú)線(xiàn)收發(fā)芯片XN297LBW

這篇具有很好參考價(jià)值的文章主要介紹了普冉PY32系列(八) GPIO模擬和硬件SPI方式驅(qū)動(dòng)無(wú)線(xiàn)收發(fā)芯片XN297LBW。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

目錄

  • 普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU簡(jiǎn)介
  • 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode開(kāi)發(fā)環(huán)境
  • 普冉PY32系列(三) PY32F002A資源實(shí)測(cè) - 這個(gè)型號(hào)不簡(jiǎn)單
  • 普冉PY32系列(四) PY32F002A/003/030的時(shí)鐘設(shè)置
  • 普冉PY32系列(五) 使用JLink RTT代替串口輸出日志
  • 普冉PY32系列(六) 通過(guò)I2C接口驅(qū)動(dòng)PCF8574擴(kuò)展的1602LCD
  • 普冉PY32系列(七) SOP8,SOP10,SOP16封裝的PY32F002A/PY32F003管腳復(fù)用
  • 普冉PY32系列(八) GPIO模擬和硬件SPI方式驅(qū)動(dòng)無(wú)線(xiàn)收發(fā)芯片XN297LBW
  • 普冉PY32系列(九) GPIO模擬和硬件SPI方式驅(qū)動(dòng)無(wú)線(xiàn)收發(fā)芯片XL2400
  • 普冉PY32系列(十) 基于PY32F002A的6+1通道遙控小車(chē)I - 綜述篇
  • 普冉PY32系列(十一) 基于PY32F002A的6+1通道遙控小車(chē)II - 控制篇
  • 普冉PY32系列(十二) 基于PY32F002A的6+1通道遙控小車(chē)III - 驅(qū)動(dòng)篇

XN297LBW

XN297LBW 是一個(gè)SOP8封裝的2.4GHz頻段無(wú)線(xiàn)收發(fā)芯片, 價(jià)格在1元左右, 適用于低成本應(yīng)用. 雖然磐啟已經(jīng)發(fā)布了 XN297L 的下一代產(chǎn)品 PAN1026, 但是市面上基本上見(jiàn)不到后者的身影, 零售能買(mǎi)到的還是 XN297L.

普冉PY32系列(八) GPIO模擬和硬件SPI方式驅(qū)動(dòng)無(wú)線(xiàn)收發(fā)芯片XN297LBW

生產(chǎn)商是上海磐啟, 產(chǎn)品頁(yè)地址: https://wiki.panchip.com/ble-lite/2-4g-t-rx/xn297l_series/

磐啟對(duì) XN297L 的產(chǎn)品介紹: "工作在 2.400~2.483GHz 世界通用 ISM 頻段的單片無(wú)線(xiàn)收發(fā)芯片, XN297L采用嵌入式基帶協(xié)議引擎, 適用于超低功耗無(wú)線(xiàn)應(yīng)用. 采用 GFSK 調(diào)制, 可配置頻率信道, 輸出功率和接口數(shù)據(jù)速率等射頻參數(shù). XN297L 支持 2Mbps, 1Mbps 和 250Kbps 的數(shù)據(jù)速率. 對(duì)于長(zhǎng)距離應(yīng)用, 輸出功率可以調(diào)節(jié)高達(dá) 11dBm, 對(duì)于短距離和超低功率應(yīng)用, 輸出功率可以低至-23dBm."

XN297LBW 主要特性

  • 無(wú)線(xiàn)
    • 通信頻段:2.400GHz~2.483GHz
    • 數(shù)據(jù)速率:2Mbps,1Mbps,250Kbps
    • 調(diào)制方式:GFSK
  • 發(fā)射器
    • 輸出功率:11, 9, 5, -1, -10 or -23dBm
    • 18mA@2dBm
    • 30mA@9dBm
  • 接收器
    • -83dBm@2Mbps
    • -87dBm@1Mbps
    • -91dBm@250Kbps
  • 協(xié)議引擎
    • 支持1到32字節(jié)或64字節(jié)數(shù)據(jù)長(zhǎng)度
    • 支持自動(dòng)應(yīng)答及自動(dòng)重傳
    • 6個(gè)接收數(shù)據(jù)通道構(gòu)成1:6的星狀網(wǎng)絡(luò)
  • 電源管理
    • 工作電壓:2.3~3.3V
    • 2uA斷電模式
    • 30uA待機(jī)-Ⅰ模式
  • 主機(jī)接口
    • 支持3引腳SPI, 4Mbps SPI接口速率
    • 支持兩個(gè)獨(dú)立的32字節(jié)TX和RX FIFOs
    • 支持一個(gè)64字節(jié)的TX和RX FIFOs
  • 封裝
    • SOP8

這里要注意的幾點(diǎn):

  1. 工作電壓是3.3V, 不要錯(cuò)接5V.
  2. SPI速率為4MHz, 實(shí)測(cè)上限不會(huì)比4MHz高多少, 在6MHz頻率時(shí)大概率SPI通信錯(cuò)誤導(dǎo)致不能工作.
  3. TX FIFO 與NRF24L01相比只有兩個(gè)32字節(jié), 而NRF24L01是3個(gè)32字節(jié). 性能相對(duì)縮水.

PIN腳定義和應(yīng)用電路

PIN腳定義

  • VDD 和 VSS 分別接 VCC 和 GND
  • XC1 和 XC2 接晶振
  • ANT 接天線(xiàn)
  • 用于MCU接口通信的只有 CSN, SCK 和 DATA 這三個(gè)PIN

普冉PY32系列(八) GPIO模擬和硬件SPI方式驅(qū)動(dòng)無(wú)線(xiàn)收發(fā)芯片XN297LBW

應(yīng)用電路

普冉PY32系列(八) GPIO模擬和硬件SPI方式驅(qū)動(dòng)無(wú)線(xiàn)收發(fā)芯片XN297LBW

模塊實(shí)物

嘉立創(chuàng)打樣的測(cè)試模塊 (項(xiàng)目地址 https://oshwhub.com/iosetting/xn297lbw-xl2400-evb)

普冉PY32系列(八) GPIO模擬和硬件SPI方式驅(qū)動(dòng)無(wú)線(xiàn)收發(fā)芯片XN297LBW

使用PY32F0驅(qū)動(dòng)XN297LBW

XN297L最新的SDK可以從磐啟的論壇下載 論壇?BLE-Lite系列2.4GHz TRX?XN297L?XN297L_SDK. 因?yàn)槊嫦虻闹饕堑统杀緫?yīng)用, 大多數(shù)搭配的MCU為廉價(jià)的8位8051, 不一定有硬件SPI, 為了保證兼容在SDK中使用的都是GPIO模擬SPI方式進(jìn)行驅(qū)動(dòng). 但是實(shí)際上是可以通過(guò)硬件SPI方式進(jìn)行驅(qū)動(dòng)的.

以下分別對(duì)GPIO模擬和硬件SPI方式的驅(qū)動(dòng)進(jìn)行介紹.

硬件準(zhǔn)備

  • XN297LBW模塊
  • PY32F002A/PY32F003/PY32F030 系列MCU的開(kāi)發(fā)板, 建議在驗(yàn)證階段使用 20PIN 及以上封裝的型號(hào), 避免PIN腳復(fù)用引起的干擾. 跑通后再遷移到低PIN型號(hào)
  • USB2TTL模塊, 用于觀察輸出
  • 以上硬件需要兩套, 測(cè)試中分別用于接收和發(fā)送

下面以PY32F002A為例. 代碼不需調(diào)整可以直接運(yùn)行于 PY32F003x 和 PY32F030x 系列的其它型號(hào).

GPIO模擬方式

接線(xiàn)

注意電源使用3.3V

PY32          XN297LBW SOP8
PA1   ------> CLK/SCK
PA6   ------> CSN/NSS
PA7   ------> DATA/MOSI

              USB2TTL
PA2(TX) ----> RX
PA3(RX) ----> TX

代碼說(shuō)明

SDK代碼中使用的MCU是STM8L, 需要遷移到 PY32F002A.

將 xn297l.h 中的 GPIO 設(shè)置換為PY32F002A的PIN腳

#define XN297L_DATA_OUT()        LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_7, LL_GPIO_MODE_OUTPUT)
#define XN297L_DATA_IN()         LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_7, LL_GPIO_MODE_INPUT)
#define XN297L_DATA_LOW()        LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_7)
#define XN297L_DATA_HIGH()       LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_7)
#define XN297L_DATA_READ()       LL_GPIO_IsInputPinSet(GPIOA, LL_GPIO_PIN_7)

#define XN297L_SCK_LOW()         LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_1)
#define XN297L_SCK_HIGH()        LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_1)

#define XN297L_CSN_LOW()         LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_6)
#define XN297L_CSN_HIGH()        LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_6)

#define XN297L_CE_LOW()          XN297L_WriteReg(XN297L_CMD_CE_FSPI_OFF, 0)
#define XN297L_CE_HIGH()         XN297L_WriteReg(XN297L_CMD_CE_FSPI_ON, 0)

在 main.c 中增加GPIO初始化

static void APP_GPIOConfig(void)
{
  LL_GPIO_InitTypeDef GPIO_InitStruct;

  /* PA1 CLK */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_1;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  /* PA6 CSN */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_6;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  /* PA7 DATA */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_7;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_INPUT;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

使用GPIO模擬SPI的字節(jié)寫(xiě)

/**
 * Emulate SPI Write on GPIO pins
 */
void XN297L_WriteByte(uint8_t value)
{
    uint8_t i = 0;
    XN297L_SCK_LOW();
    XN297L_DATA_OUT();
    for (i = 0; i < 8; i++)
    {
        XN297L_SCK_LOW();
        if (value & 0x80)
        {
            XN297L_DATA_HIGH();
        }
        else
        {
            XN297L_DATA_LOW();
        }
        XN297L_SCK_HIGH();
        value = value << 1;
    }
    XN297L_SCK_LOW();
}

模擬字節(jié)讀. 這里有個(gè)細(xì)節(jié), 在XN297L_SCK_HIGH();之后加一個(gè)__NOP();, 如果沒(méi)有這個(gè)NOP(), PY32F0在低頻率(8MHz和24MHz)的時(shí)候容易產(chǎn)生讀取錯(cuò)誤.

/**
 * Emulate SPI Read on GPIO pins
 */
uint8_t XN297L_ReadByte(void)
{
    uint8_t i = 0, RxData = 0;

    XN297L_DATA_IN();
    for (i = 0; i < 8; i++)
    {
        RxData = RxData << 1;
        XN297L_SCK_HIGH();
        __NOP();
        if (XN297L_DATA_READ())
        {
            RxData |= 0x01;
        }
        else
        {
            RxData &= 0xfe;
        }
        XN297L_SCK_LOW();
    }
    return RxData;
}

XN297L 的初始化. 這部分是相對(duì)固定的流程, 可以根據(jù)自己的需要進(jìn)行調(diào)整, 但是在測(cè)試階段務(wù)必保持接收端和發(fā)送端的配置一致. 這里在SDK的代碼上做了一些修改, 開(kāi)啟了發(fā)送的重試和ACK.

// 這部分來(lái)自于手冊(cè) "XN297L 軟件設(shè)計(jì)和調(diào)試參考"
const uint8_t 
    BB_cal_data[]    = {0x12,0xED,0x67,0x9C,0x46},
    RF_cal_data[]    = {0xF6,0x3F,0x5D},
    RF_cal2_data[]   = {0x45,0x21,0xEF,0x2C,0x5A,0x42},
    Dem_cal_data[]   = {0x01},
    Dem_cal2_data[]  = {0x0B,0xDF,0x02};

void XN297L_Init(void)
{
    XN297L_WriteReg(XN297L_CMD_RST_FSPI, 0x5A); // Soft reset
    XN297L_WriteReg(XN297L_CMD_RST_FSPI, 0XA5);

    XN297L_WriteReg(XN297L_CMD_FLUSH_TX, 0);
    XN297L_WriteReg(XN297L_CMD_FLUSH_RX, 0);
    XN297L_WriteReg(XN297L_CMD_W_REGISTER | XN297L_REG_STATUS, 0x70);       // Clear status flags
    XN297L_WriteReg(XN297L_CMD_W_REGISTER | XN297L_REG_EN_AA, 0x3F);        // AutoAck on all pipes
    XN297L_WriteReg(XN297L_CMD_W_REGISTER | XN297L_REG_EN_RXADDR, 0x3F);    // Enable all pipes (P0 ~ P5, bit0 ~ bit5)
    XN297L_WriteReg(XN297L_CMD_W_REGISTER | XN297L_REG_SETUP_AW, XN297L_SETUP_AW_5BYTE); // Address width
    XN297L_WriteReg(XN297L_CMD_W_REGISTER | XN297L_REG_RF_CH, 78);          // Channel 78, 2478M HZ
    XN297L_WriteReg(XN297L_CMD_W_REGISTER | XN297L_REG_RX_PW_P0, XN297L_PLOAD_WIDTH ); // Payload width of P0
    XN297L_WriteReg(XN297L_CMD_W_REGISTER | XN297L_REG_RX_PW_P1, XN297L_PLOAD_WIDTH ); // Payload width of P1
    XN297L_WriteReg(XN297L_CMD_W_REGISTER | XN297L_REG_RX_PW_P2, XN297L_PLOAD_WIDTH ); // Payload width of P2
    XN297L_WriteReg(XN297L_CMD_W_REGISTER | XN297L_REG_RX_PW_P3, XN297L_PLOAD_WIDTH ); // Payload width of P3
    XN297L_WriteReg(XN297L_CMD_W_REGISTER | XN297L_REG_RX_PW_P4, XN297L_PLOAD_WIDTH ); // Payload width of P4
    XN297L_WriteReg(XN297L_CMD_W_REGISTER | XN297L_REG_RX_PW_P5, XN297L_PLOAD_WIDTH ); // Payload width of P5

    XN297L_WriteFromBuf(XN297L_CMD_W_REGISTER | XN297L_REG_BB_CAL,    BB_cal_data,  sizeof(BB_cal_data));
    XN297L_WriteFromBuf(XN297L_CMD_W_REGISTER | XN297L_REG_RF_CAL2,   RF_cal2_data, sizeof(RF_cal2_data));
    XN297L_WriteFromBuf(XN297L_CMD_W_REGISTER | XN297L_REG_DEM_CAL,   Dem_cal_data, sizeof(Dem_cal_data));
    XN297L_WriteFromBuf(XN297L_CMD_W_REGISTER | XN297L_REG_RF_CAL,    RF_cal_data,  sizeof(RF_cal_data));
    XN297L_WriteFromBuf(XN297L_CMD_W_REGISTER | XN297L_REG_DEM_CAL2,  Dem_cal2_data,sizeof(Dem_cal2_data));
    XN297L_WriteReg(XN297L_CMD_W_REGISTER | XN297L_REG_DYNPD, 0x00); // Dynamic payload width: off
    XN297L_WriteReg(XN297L_CMD_W_REGISTER | XN297L_REG_RF_SETUP,  XN297L_RF_POWER_P_9|XN297L_RF_DR_1M); // 9dbm 1Mbps
    XN297L_WriteReg(XN297L_CMD_ACTIVATE, 0x73);

    XN297L_WriteReg(XN297L_CMD_W_REGISTER | XN297L_REG_SETUP_RETR, 0x10|0x05); // Retry interval 500μs, 5 times

    if(XN297L_PLOAD_WIDTH >32)
    {
        XN297L_WriteReg(XN297L_CMD_W_REGISTER | XN297L_REG_FEATURE, XN297L_FEATURE_BIT5_CE_SOFT|XN297L_FEATURE_BIT43_DATA_64BYTE);
    }
    else
    {
        XN297L_WriteReg(XN297L_CMD_W_REGISTER | XN297L_REG_FEATURE, XN297L_FEATURE_BIT5_CE_SOFT);
    }
}

數(shù)據(jù)發(fā)送函數(shù). 因?yàn)榍懊骈_(kāi)啟了重試和ACK, 這里做了一個(gè)等待發(fā)送結(jié)果的輪詢(xún)和超時(shí)判斷

uint8_t XN297L_TxData(uint8_t *ucPayload, uint8_t length)
{
    uint8_t y = 100, status = 0;
    XN297L_CE_HIGH();
    __NOP();
    XN297L_WriteFromBuf(XN297L_CMD_W_TX_PAYLOAD, ucPayload, length);
    // Retry until timeout
    while (y--)
    {
        LL_mDelay(1);
        status = XN297L_ReadStatus();
        // If TX successful or retry timeout, exit
        if ((status & (XN297L_FLAG_MAX_RT | XN297L_FLAG_TX_DS)) != 0)
        {
            //printf(" %d %02x\r\n", y, status);
            break;
        }
    }
    XN297L_WriteReg(XN297L_CMD_FLUSH_TX, 0);
    XN297L_WriteReg(XN297L_CMD_W_REGISTER | XN297L_REG_STATUS, 0x70);
    XN297L_CE_LOW();
    return status;
}

數(shù)據(jù)接收. 因?yàn)榻邮帐褂玫氖禽喸?xún), 所以這里只是簡(jiǎn)單地判斷了接收狀態(tài), 在收到數(shù)據(jù)時(shí)讀取數(shù)據(jù).

uint8_t XN297L_DumpRxData(void)
{
    uint8_t status, rxplWidth;
    status = XN297L_ReadStatus();
    if (status & XN297L_FLAG_RX_DR)
    {
        XN297L_WriteReg(XN297L_CMD_W_REGISTER | XN297L_REG_STATUS, status);
        rxplWidth = XN297L_ReadReg(XN297L_CMD_R_RX_PL_WID);
        XN297L_ReadToBuf(XN297L_CMD_R_RX_PAYLOAD, xbuf, rxplWidth);
    }
    return status;
}

完整代碼

XN297L 示例代碼的 GitHub 倉(cāng)庫(kù)地址: https://github.com/IOsetting/py32f0-template/tree/main/Examples/PY32F0xx/LL/GPIO/XN297LBW_Wireless

運(yùn)行測(cè)試

修改 main.c 中的模式設(shè)置, 0為接收, 1為發(fā)送, 分別寫(xiě)入至兩個(gè)PY32F002A開(kāi)發(fā)板, 觀察UART的輸出.

// 0:RX, 1:TX
#define XN297L_MODE 0

接收端在每次接收到數(shù)據(jù)時(shí), 輸出第1,2,31個(gè)字節(jié)的值; 發(fā)送端每發(fā)送255組數(shù)據(jù)(每組32字節(jié))后, 會(huì)顯示發(fā)送成功的個(gè)數(shù)(十六進(jìn)制), 這個(gè)輸出可以用于計(jì)算發(fā)送成功率, 以及發(fā)送速度.

硬件SPI方式

接線(xiàn)

接線(xiàn)方式使用4線(xiàn)制全雙工, PY32的MOSI和MISO都接到XN297LBW的DATA, 但是在MOSI(PA7)上串一個(gè)1K的電阻. 對(duì)于使用SPI協(xié)議的三線(xiàn)連接, 如果半雙工SPI有問(wèn)題, 都可以用這種接線(xiàn)試試全雙工方式通信. 從實(shí)際測(cè)試看, XN297LBW 支持這種接線(xiàn)方式.

PY32                XN297LBW SOP8
PA0   ------------> DATA/MOSI
PA7   ---> 1KR ---> DATA/MOSI
PA1   ------------> CLK/SCK
PA6   ------------> CSN/NSS

                    USB2TTL
PA2(TX) ----------> RX
PA3(RX) ----------> TX

代碼說(shuō)明

SPI接口的初始化. 注意SPI的時(shí)鐘頻率不要超過(guò)4MHz

/**
 * SPI1 Alternative Function Pins
 * SPI1_SCK:  PA1_AF0, PA2_AF10, PA5_AF0, PA9_AF10, PB3_AF0
 * SPI1_MISO: PA0_AF10, PA6_AF0, PA7_AF10, PA11_AF0, PA13_AF10, PB4_AF0
 * SPI1_MOSI: PA1_AF10, PA2_AF0, PA3_AF10, PA7_AF0, PA8_AF10, PA12_AF0, PB5_AF0
 * SPI1_NSS:  PA4_AF0, PA10_AF10, PA15_AF0, PB0_AF0, PF1_AF10, PF3_AF10
*/
static void APP_SPI_Config(void)
{
  LL_SPI_InitTypeDef SPI_InitStruct = {0};
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

  LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_SPI1);

  // PA1 SCK
  GPIO_InitStruct.Pin = LL_GPIO_PIN_1;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  // PA0 MISO
  GPIO_InitStruct.Pin = LL_GPIO_PIN_0;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_10;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  // PA7 MOSI
  GPIO_InitStruct.Pin = LL_GPIO_PIN_7;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  /*
   * Full duplex mode, MOSI and MISO both connect to DATA,
   * Add one 1KR between MOSI and DATA
  */
  SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
  SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;
  SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;
  SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW;
  SPI_InitStruct.ClockPhase = LL_SPI_PHASE_1EDGE;
  SPI_InitStruct.NSS = LL_SPI_NSS_SOFT;
  // SPI的時(shí)鐘頻率不要超過(guò)4MHz
  SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV16;
  SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
  LL_SPI_Init(SPI1, &SPI_InitStruct);
  LL_SPI_Enable(SPI1);
}

硬件SPI方式的字節(jié)讀寫(xiě)

uint8_t SPI_TxRxByte(uint8_t data)
{
  uint8_t SPITimeout = 0xFF;
  /* Check the status of Transmit buffer Empty flag */
  while (READ_BIT(SPI1->SR, SPI_SR_TXE) == RESET)
  {
    if (SPITimeout-- == 0)
      return 0;
  }
  LL_SPI_TransmitData8(SPI1, data);
  SPITimeout = 0xFF;
  while (READ_BIT(SPI1->SR, SPI_SR_RXNE) == RESET)
  {
    if (SPITimeout-- == 0)
      return 0;
  }
  // Read from RX buffer
  return LL_SPI_ReceiveData8(SPI1);
}

對(duì)應(yīng)XN297L的命令讀寫(xiě)改造為調(diào)用硬件SPI讀寫(xiě)函數(shù)

uint8_t XN297L_WriteReg(uint8_t reg, uint8_t value)
{
    uint8_t reg_val;
    XN297L_CSN_LOW();
    SPI_TxRxByte(reg);
    reg_val = SPI_TxRxByte(value);
    XN297L_CSN_HIGH();
    return reg_val;
}

uint8_t XN297L_ReadReg(uint8_t reg)
{
    uint8_t reg_val;
    XN297L_CSN_LOW();
    SPI_TxRxByte(reg);
    reg_val = SPI_TxRxByte(XN297L_CMD_NOP);
    XN297L_CSN_HIGH();
    return reg_val;
}

完整代碼

XN297L 示例代碼的 GitHub 倉(cāng)庫(kù)地址: https://github.com/IOsetting/py32f0-template/tree/main/Examples/PY32F0xx/LL/SPI/XN297L_Wireless

運(yùn)行測(cè)試

和GPIO模擬方式的一樣, 修改 main.c 中的模式設(shè)置, 0為接收, 1為發(fā)送, 分別寫(xiě)入至兩個(gè)PY32F002A開(kāi)發(fā)板, 觀察UART的輸出.

// 0:RX, 1:TX
#define XN297L_MODE 0

利用FIFO隊(duì)列提升發(fā)送速度

在 NRF24L01 的使用中, 可以通過(guò) "直接寫(xiě)入TX FIFO -> 通過(guò) FLAG 觀察 TX FIFO 是否寫(xiě)滿(mǎn)判斷是繼續(xù)寫(xiě)入還是阻塞等待" 的方式提升發(fā)送速度. XN297L 的 TX FIFO 隊(duì)列包含兩組 32 個(gè)字節(jié), 也可以通過(guò)這種方式進(jìn)行加速.

相關(guān)的函數(shù)

ErrorStatus XN297L_TxFast(const uint8_t *ucPayload, uint8_t length)
{
    //Blocking only if FIFO is full. This will loop and block until TX is successful or fail
    while ((XN297L_ReadStatus() & XN297L_FLAG_TX_FULL)) {
        if (xn297l_state & XN297L_FLAG_MAX_RT) {
            return ERROR;
        }
    }
    XN297L_WriteFromBuf(XN297L_CMD_W_TX_PAYLOAD, ucPayload, length);
    XN297L_CE_HIGH();
    return SUCCESS;
}

// 用于 MAX_RT 狀態(tài)清除標(biāo)志位
void XN297L_ReuseTX(void)
{
    XN297L_WriteReg(XN297L_CMD_W_REGISTER | XN297L_REG_STATUS, XN297L_FLAG_MAX_RT); //Clear max retry flag
    XN297L_CE_LOW();
    XN297L_CE_HIGH();
}

使用方式: 在發(fā)送循環(huán)中調(diào)用 XN297L_TxFast() 進(jìn)行發(fā)送, 在遇到錯(cuò)誤時(shí), 用 XN297L_ReuseTX() 重置狀態(tài)

if (XN297L_TxFast(tmp, XN297L_PLOAD_WIDTH) == SUCCESS)
{
  j++;
}
else
{
  XN297L_ReuseTX();
}

從實(shí)際測(cè)試結(jié)果看, 用 XN297L_TxFast() 發(fā)送相比普通發(fā)送方式有10%的性能提升.文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-710704.html

到了這里,關(guān)于普冉PY32系列(八) GPIO模擬和硬件SPI方式驅(qū)動(dòng)無(wú)線(xiàn)收發(fā)芯片XN297LBW的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 普冉PY32系列(三) PY32F002A 資源實(shí)測(cè) - 這個(gè)型號(hào)不簡(jiǎn)單

    普冉PY32系列(三) PY32F002A 資源實(shí)測(cè) - 這個(gè)型號(hào)不簡(jiǎn)單

    普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU簡(jiǎn)介 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode開(kāi)發(fā)環(huán)境 普冉PY32系列(三) PY32F002A資源實(shí)測(cè) - 這個(gè)型號(hào)不簡(jiǎn)單 普冉PY32系列(四) PY32F002A/003/030的時(shí)鐘設(shè)置 普冉PY32系列(五) 使用JLink RTT代替串口輸出日志 普冉PY32系列(六) 通過(guò)I2C接口驅(qū)動(dòng)PCF8574擴(kuò)

    2023年04月19日
    瀏覽(56)
  • 普冉PY32系列(十四) 從XL2400遷移到XL2400P

    普冉PY32系列(十四) 從XL2400遷移到XL2400P

    普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU簡(jiǎn)介 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode開(kāi)發(fā)環(huán)境 普冉PY32系列(三) PY32F002A資源實(shí)測(cè) - 這個(gè)型號(hào)不簡(jiǎn)單 普冉PY32系列(四) PY32F002A/003/030的時(shí)鐘設(shè)置 普冉PY32系列(五) 使用JLink RTT代替串口輸出日志 普冉PY32系列(六) 通過(guò)I2C接口驅(qū)動(dòng)PCF8574擴(kuò)

    2024年02月04日
    瀏覽(17)
  • 普冉PY32系列(十) 基于PY32F002A的6+1通道遙控小車(chē)I - 綜述篇

    普冉PY32系列(十) 基于PY32F002A的6+1通道遙控小車(chē)I - 綜述篇

    普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU簡(jiǎn)介 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode開(kāi)發(fā)環(huán)境 普冉PY32系列(三) PY32F002A資源實(shí)測(cè) - 這個(gè)型號(hào)不簡(jiǎn)單 普冉PY32系列(四) PY32F002A/003/030的時(shí)鐘設(shè)置 普冉PY32系列(五) 使用JLink RTT代替串口輸出日志 普冉PY32系列(六) 通過(guò)I2C接口驅(qū)動(dòng)PCF8574擴(kuò)

    2024年02月05日
    瀏覽(20)
  • 普冉PY32系列(十一) 基于PY32F002A的6+1通道遙控小車(chē)II - 控制篇

    普冉PY32系列(十一) 基于PY32F002A的6+1通道遙控小車(chē)II - 控制篇

    普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU簡(jiǎn)介 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode開(kāi)發(fā)環(huán)境 普冉PY32系列(三) PY32F002A資源實(shí)測(cè) - 這個(gè)型號(hào)不簡(jiǎn)單 普冉PY32系列(四) PY32F002A/003/030的時(shí)鐘設(shè)置 普冉PY32系列(五) 使用JLink RTT代替串口輸出日志 普冉PY32系列(六) 通過(guò)I2C接口驅(qū)動(dòng)PCF8574擴(kuò)

    2024年02月05日
    瀏覽(37)
  • stm32 GPIO模擬SPI接口實(shí)現(xiàn)雙機(jī)通信

    一、SPI協(xié)議簡(jiǎn)介 ? ? 一般主從方式工作,這種模式通常有一個(gè)主設(shè)備和一個(gè)或多個(gè)從設(shè)備,通常采用的是4根線(xiàn),它們是MISO(主機(jī)輸入從機(jī)輸出)、MOSI(主機(jī)輸出,針對(duì)主機(jī)來(lái)說(shuō))、SCLK(時(shí)鐘,主機(jī)產(chǎn)生)、CS(片選,一般由主機(jī)發(fā)送或者直接使能,通常為低電平有效) ●

    2023年04月08日
    瀏覽(18)
  • STM32的硬件SPI驅(qū)動(dòng)AD7124的方法

    STM32的硬件SPI驅(qū)動(dòng)AD7124的方法

    AD7124是一款適合高精度測(cè)量應(yīng)用的低功耗、低噪聲、完整模擬前端。該器件內(nèi)置一個(gè)低噪聲24位Σ-Δ型模數(shù)轉(zhuǎn)換器(ADC),可配置來(lái)提供8個(gè)差分輸入或15個(gè)單端或偽差分輸入。片內(nèi)低噪聲級(jí)確保ADC中可直接輸入小信號(hào)。可用于溫度測(cè)量、壓力測(cè)量、工業(yè)過(guò)程控制、儀器儀表和只能

    2024年02月07日
    瀏覽(173)
  • STM32F103硬件SPI驅(qū)動(dòng)ADS1256

    STM32F103硬件SPI驅(qū)動(dòng)ADS1256

    最近實(shí)驗(yàn)室有幾個(gè)項(xiàng)目都需要用到高分辨率AD轉(zhuǎn)換,于是就開(kāi)始了ADS1256的開(kāi)發(fā)。 新手,焊得丑,見(jiàn)諒(能用就行) 二: 本以為很容易就能做完,結(jié)果被采樣速率的問(wèn)題困擾了很久。 代碼如下,使用2.5V基準(zhǔn)源進(jìn)行測(cè)試,結(jié)果在讀ADS時(shí)經(jīng)常出現(xiàn)讀出0xFFFFFF的情況,只能忍住悲傷

    2024年02月12日
    瀏覽(112)
  • stm32 hal庫(kù)硬件spi(軟件spi)驅(qū)動(dòng)1.8寸tft—lcd屏幕

    stm32 hal庫(kù)硬件spi(軟件spi)驅(qū)動(dòng)1.8寸tft—lcd屏幕

    屏幕是嵌入式開(kāi)發(fā)中的一個(gè)重要的部分,cdsn上有許多解釋原理的,還有很多是采用正點(diǎn)原子的屏幕來(lái)驅(qū)動(dòng)的,對(duì)于剛剛?cè)腴T(mén)不久的我們可能沒(méi)有資金去購(gòu)買(mǎi)較為昂貴的屏幕。而對(duì)于底層原理我們暫時(shí)也不必了解的那么深入,能點(diǎn)亮屏幕就是我們最大的快樂(lè)。 除了中景園的資

    2024年02月03日
    瀏覽(23)
  • STM32配合CubeMX硬件SPI驅(qū)動(dòng)0.96寸OLED

    STM32配合CubeMX硬件SPI驅(qū)動(dòng)0.96寸OLED

    目錄 一、簡(jiǎn)單介紹 1.1 OLED 1.2 SPI協(xié)議 接口 優(yōu)點(diǎn) 缺點(diǎn) 數(shù)據(jù)傳輸 二、實(shí)戰(zhàn) 2.1 工程配置 2.2?測(cè)試工程 2.3 波形分析 三、驅(qū)動(dòng)OLED 3.1?初始化代碼 3.2 清屏函數(shù) 3.3 設(shè)置坐標(biāo)函數(shù) 3.4 顯示字符函數(shù) 3.5 顯示字符串函數(shù) 3.6 顯示圖片函數(shù) 附錄 驅(qū)動(dòng)代碼文件 oled.c oled.h f6x8.h 1.1 OLED 有機(jī)發(fā)

    2024年02月02日
    瀏覽(25)
  • 基礎(chǔ)篇010.2 STM32驅(qū)動(dòng)RC522 RFID模塊之二:STM32硬件SPI驅(qū)動(dòng)RC522

    基礎(chǔ)篇010.2 STM32驅(qū)動(dòng)RC522 RFID模塊之二:STM32硬件SPI驅(qū)動(dòng)RC522

    目錄 1. 實(shí)驗(yàn)硬件及原理圖 1.1 RFID硬件 1.2 硬件原理圖 2. 單片機(jī)與RFID硬件模塊分析 3. 利用STM32CubeMX創(chuàng)建MDK工程 3.1 STM32CubeMX工程創(chuàng)建 3.2 配置調(diào)試方式 3.3 配置時(shí)鐘電路 3.4 配置時(shí)鐘 3.5 配置GPIO 3.6 配置SPI 3.7 配置串口 3.8 項(xiàng)目配置 4. MDK工程驅(qū)動(dòng)代碼調(diào)試 4.1 按鍵、LED程序 4.1.1 Us

    2024年02月09日
    瀏覽(22)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包