一、前言
TWI(Two wire Serial Interface):twi接口是對I2C總線接口的繼承和發展,完全兼容I2C總線
Nordic的TWI外設主要分成兩類,TWIM
(基於EasyDMA的主設備Master) TWIS
(基於EasyDMA的從設備Slave)
ps:如有錯誤,請留言指正,謝謝
二、工作原理
功能特點
- 兼容I2C總線
- 可選速率 100kbps/250kbps/400kbps
- EasyDMA進行RAM數據與寄存器的傳輸
- 可映射到任意的GPIO引腳
原理框圖
一主多從應用案例
TWI主機可同時掛載多個從機,主機通過從機唯一分配的地址進行尋址訪問,總線需加上拉電阻以保證其驅動能力
數據通信過程
寫數據
- TWI主機寫數據通過
STARTTX
任務進行觸發,最終通過STOP
結束任務- 從機的地址尋址成功後,通過
TXD.PTR
寄存器指向的RAM地址,調製發送數據- 發送時可被
SUSPEND
任務掛起,掛起期間總線會保持,在生效RESUME
任務後可繼續通信- 當發送最後一個字節時,TWIM會產生一個
LASTTX
事件,必須發出STOP
任務結束一次通信(不會自動停止總線通信)- 僅通信
RESUME
釋放後才能發送STOP
任務
讀數據
- TWI主機讀數據通過
STARTRX
任務觸發,通過STOP
借結束任務- 讀取到的數據將儲存到
RXD.PTR
寄存器指向的RAM地址中,數據接收完成後主機產生一個NACK- 掛起任務
SUSPEND
觸發後,將會產生一個SUSPENDED
事件,此事件可用於同步軟件- 當TWI主機準備接收最後一個字節時,會產生一個
LASTRX
事件- TWI master在被掛起時無法停止,因此必須在TWI master恢復後發出STOP任務
三、寄存器
- SHORTS:循環模式控制,寫1使能發送/接收最後字節的
LASTTX
/LASTRX
事件後,自動觸發如開啓/掛起/結束任務 - INTEN:中斷控制寄存器,寫1使能中斷,寫0禁用中斷(按位配置中斷
STOPPED/ERROR/SUSPENDED/RXSTARTED/TXSTARTED/LASTRX/LASTTX
) - INTENSET:中斷使能寄存器,寫1有效
- INTENCLR:中斷禁用寄存器,寫1有效
- ERRORSRC:錯誤狀態寄存器,寫1清狀態
- ENABLE:TWIM外設使能寄存器
- PLSEL.SCL:關聯SCL時鐘引腳,低4位有效
- PLSEL.SDA:關聯SDA數據引腳,低4位有效
- FREQUENCY:TWI通信速率選擇
100k
250k
400k
- RXD.PTR:接收數據寄存器,指向RXD接收緩存
- RXD.MAXCNT:接收數據緩存區最大長度
- RXD.AMOUNT:最近一次數據通信的接收傳輸字節長度
- RXD.LIST:EasyDMA列表類型,寫1使用arraylist接收緩存,觸發
START
任務時無需更新PTR數據指針寄存器,類似DMA串口中雙緩存循環讀取 - TXD.PTR:發送數據寄存器,指向TXD發送緩存
- TXD.MAXCNT:需要發送數據緩存的最大長度
- TXD.AMOUNT:最近一次數據通信的發送傳輸字節長度
- TXD.LIST:EasyDMA列表類型,寫1使用arraylist發送緩存,觸發
START
任務時無需更新PTR數據指針寄存器,類似DMA串口中雙緩存循環發送 - ADDRESS:TWI總線的尋址地址,最低位爲讀寫位
四、相關接口
SPIM的驅動目錄在modules\nrfx\drivers\src\nrfx_twim.c中
- nrfx_twim_init:初始化twim,形參
nrfx_twim_config_t p_config
傳入引腳的映射關係與TWI的參數(通信速率、中斷優先級);函數指針nrfx_twim_evt_handler_t handler
用於定義事件回調(數據的發送與接收)
nrfx_err_t nrfx_twim_init(nrfx_twim_t const * p_instance,
nrfx_twim_config_t const * p_config,
nrfx_twim_evt_handler_t event_handler,
void * p_context)
- nrfx_twim_uninit:禁用twim外設,系統進入低功耗的時候可以調用
void nrfx_twim_uninit(nrfx_twim_t const * p_instance)
- nrfx_twim_xfer:數據傳輸接口,形參
nrfx_twim_xfer_desc_t const * p_xfer_desc
定義了發送TX與接收RX的緩存與長度
nrfx_err_t nrfx_twim_xfer(nrfx_twim_t const * p_instance,
nrfx_twim_xfer_desc_t const * p_xfer_desc,
uint32_t flags)
五、代碼實例
打開工程目錄 examples\peripheral\twi_master_with_twis_slave.eww,選擇pca10040
貼上例程代碼
/*
* 初始化TWI master
*/
static ret_code_t twi_master_init(void)
{
ret_code_t ret;
const nrf_drv_twi_config_t config =
{
.scl = TWI_SCL_M,//選擇pin腳
.sda = TWI_SDA_M,
.frequency = NRF_DRV_TWI_FREQ_400K,//通信速率
.interrupt_priority = APP_IRQ_PRIORITY_HIGH,//優先級
.clear_bus_init = false
};
ret = nrf_drv_twi_init(&m_twi_master, &config, NULL, NULL);//調用配置驅動
if (NRF_SUCCESS == ret)
{
nrf_drv_twi_enable(&m_twi_master);//使能總線
}
return ret;
}
/*
* main接口,程序主要是通過軟件模擬了從機與主機的通信
*/
int main(void)
{
ret_code_t err_code;
bool epprom_error = 0;
/* Initialization of UART */
bsp_board_init(BSP_INIT_LEDS);
APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
/* Initializing simulated EEPROM */
err_code = eeprom_simulator_init();//模擬eeprom twis從機總線初始化
APP_ERROR_CHECK(err_code);
/* Initializing TWI master interface for EEPROM */
err_code = twi_master_init();//主機twim總線初始化
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_clock_init();//時鐘初始化
APP_ERROR_CHECK(err_code);
nrf_drv_clock_lfclk_request(NULL);
err_code = app_timer_init();//定時器初始化
APP_ERROR_CHECK(err_code);
nrf_drv_uart_config_t uart_config = NRF_DRV_UART_DEFAULT_CONFIG;//串口配置,可以使用串口命令行控制
uart_config.pseltxd = TX_PIN_NUMBER;
uart_config.pselrxd = RX_PIN_NUMBER;
uart_config.hwfc = NRF_UART_HWFC_DISABLED;
err_code = nrf_cli_init(&m_cli_uart, &uart_config, true, true, NRF_LOG_SEVERITY_INFO);
APP_ERROR_CHECK(err_code);
err_code = nrf_cli_start(&m_cli_uart);//開啓命令行cli控制
APP_ERROR_CHECK(err_code);
/* Welcome message */
NRF_LOG_RAW_INFO(
"TWIS and TWI usage example started.\r\n"
"You can access simulated EEPROM memory using <eeprom> command.\r\n"
"Execute: <eeprom -h> for more information or press the Tab button "
"to see all available commands.\r\n"
);
/* Main loop */
while (1)
{
UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
nrf_cli_process(&m_cli_uart);//處理串口命令
if (epprom_error != eeprom_simulator_error_check())//錯誤狀態查詢
{
epprom_error = eeprom_simulator_error_check();
if (epprom_error != 0)
{
NRF_LOG_RAW_INFO(
"WARNING: EEPROM transmission error detected.\r\n"
"Use 'x' command to read error word.\r\n"
);
}
}
}
}