This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] LP-MSP430FR2476:SPI 轮询接收

Guru**** 2387060 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1045302/lp-msp430fr2476-spi-polling-receive

器件型号:LP-MSP430FR2476

我将 SPI 设置为轮询模式、正如我最近的主题中所述。

LP-MSP430FR2476:SPI 发送和接收中断- MSP 低功耗微控制器论坛- MSP 低功耗微控制器- TI E2E 支持论坛

根据 MSP430用户指南 slau445i、发送和接收操作同时发生。 如果从器件需要响应、该接收字节何时会出现在 MISO 上? 在示波器视图中、我可以看到所有传输的字节、但 MISO 线路上没有活动。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <driverlib.h>
#include <msp430.h> 
#include "clock~.h"                 // Clock configurations


static uint8_t TXData = 0;           //transaction count
static uint8_t RXData = 0;           //SPI receive byte


typedef struct {
    uint8_t    Len;
    uint8_t    Data[5];
    uint8_t    RxFlag;
} spi_MaximTrans_t;

static spi_MaximTrans_t DCInit_transactions[15];


uint8_t SPI_TX_index = 0;            //byte count in transaction



/**
 *  Initialize system clocks
 */
static void init_clock(void) {
    // Configure one FRAM waitstate as required by the device datasheet for MCLK
    // operation beyond 8MHz _before_ configuring the clock system.
    FRAMCtl_configureWaitStateControl(FRAMCTL_ACCESS_TIME_CYCLES_1);

    //Set DCO FLL reference = REFO
    CS_initClockSignal(CS_FLLREF, CS_REFOCLK_SELECT,   CS_CLOCK_DIVIDER_1);
    //Set ACLK = REFO
    CS_initClockSignal(CS_ACLK,   CS_REFOCLK_SELECT,   CS_CLOCK_DIVIDER_1);

    CS_initFLLParam param = {0};
    //Set Ratio/Desired MCLK Frequency, initialize DCO, save trim values
    CS_initFLLCalculateTrim(CS_MCLK_DESIRED_FREQUENCY_IN_KHZ, CS_MCLK_FLLREF_RATIO, &param);

    //Set MCLK = REFO
    CS_initClockSignal(CS_MCLK,   CS_REFOCLK_SELECT,   CS_CLOCK_DIVIDER_1);
    //Set SMCLK = DCO
    CS_initClockSignal(CS_SMCLK,  CS_DCOCLKDIV_SELECT, CS_CLOCK_DIVIDER_1);

    //Clear all OSC fault flag
    CS_clearAllOscFlagsWithTimeout(1000);
}

/**
 *  Initialize all of the IO pins per their configuration
 */
static void init_gpio(void) {
    // Set all GPIO pins to output low to prevent floating input and reduce power consumption
    GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN_ALL8);
    GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN_ALL8);
    GPIO_setOutputLowOnPin(GPIO_PORT_P3, GPIO_PIN_ALL8);
    GPIO_setOutputLowOnPin(GPIO_PORT_P4, GPIO_PIN_ALL8);
    GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN_ALL8);
    GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN2);

    GPIO_setAsOutputPin(   GPIO_PORT_P1, GPIO_PIN_ALL8);
    GPIO_setAsOutputPin(   GPIO_PORT_P2, GPIO_PIN_ALL8);
    GPIO_setAsOutputPin(   GPIO_PORT_P3, GPIO_PIN_ALL8);
    GPIO_setAsOutputPin(   GPIO_PORT_P4, GPIO_PIN_ALL8);
    GPIO_setAsOutputPin(   GPIO_PORT_P5, GPIO_PIN_ALL8);
    GPIO_setAsOutputPin(   GPIO_PORT_P6, GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN2);

}

/*
 * Initialize the SPI peripheral on EUSCI A1
 */
void init_spi_peripheral()
{
    //Initialize Master
        EUSCI_A_SPI_initMasterParam param = {0};
        param.selectClockSource = EUSCI_A_SPI_CLOCKSOURCE_SMCLK;
        param.clockSourceFrequency = CS_getSMCLK();
        param.desiredSpiClock = 1000000;
        param.msbFirst = UCMSB;
        param.clockPhase = 0;
        param.clockPolarity = EUSCI_A_SPI_CLOCKPOLARITY_INACTIVITY_LOW;
        param.spiMode = EUSCI_A_SPI_3PIN;
        EUSCI_A_SPI_initMaster(EUSCI_A1_BASE, &param);

        EUSCI_A_SPI_enable(EUSCI_A1_BASE);

}


void SetUpTransactions(void){       //All transactions padded to 4 bytes
    //Enable keep alive mode
    DCInit_transactions[0].Len = 4;
    DCInit_transactions[0].Data[0] = 0x10;
    DCInit_transactions[0].Data[1] = 0x5;
    DCInit_transactions[0].Data[2] = 0x11;
    DCInit_transactions[0].Data[3] = 0x0;
    DCInit_transactions[0].RxFlag = 0x0;        //No Receive

    //Enable Rx Interrupt flags
    DCInit_transactions[1].Len = 4;
    DCInit_transactions[1].Data[0] = 0x4;
    DCInit_transactions[1].Data[1] = 0x88;
    DCInit_transactions[1].Data[2] = 0x0;
    DCInit_transactions[1].Data[3] = 0x0;
    DCInit_transactions[1].RxFlag = 0x0;        //No Receive

    //Clear receive buffer
    DCInit_transactions[2].Len = 4;
    DCInit_transactions[2].Data[0] = 0xe0;
    DCInit_transactions[2].Data[1] = 0x0;
    DCInit_transactions[2].Data[2] = 0x0;
    DCInit_transactions[2].Data[3] = 0x0;
    DCInit_transactions[2].RxFlag = 0x0;        //No Receive


    //Wakeup UART slave devices
    DCInit_transactions[3].Len = 4;
    DCInit_transactions[3].Data[0] = 0xe0;
    DCInit_transactions[3].Data[1] = 0x30;
    DCInit_transactions[3].Data[2] = 0x0;
    DCInit_transactions[3].Data[3] = 0x0;
    DCInit_transactions[3].RxFlag = 0x0;        //No Receive
    //2ms delay for each slave to wake up

    //Wait for all UART slave devices to wake up
    DCInit_transactions[4].Len = 4;
    DCInit_transactions[4].Data[0] = 0x01;
    DCInit_transactions[4].Data[1] = 0x0;
    DCInit_transactions[4].Data[2] = 0x0;
    DCInit_transactions[4].Data[3] = 0x91;
    DCInit_transactions[4].RxFlag = 0x1;        //Receive of 0x21 expected

    //Read message command. This was added to see a SPI receive byte on the MSP430
    //Without this, there was no change in the SPI receive buffer.


    //End of UART slave device wake-up period
    DCInit_transactions[5].Len = 4;
    DCInit_transactions[5].Data[0] = 0x0e;
    DCInit_transactions[5].Data[1] = 0x10;
    DCInit_transactions[5].Data[2] = 0x0;
    DCInit_transactions[5].Data[3] = 0x0;
    DCInit_transactions[5].RxFlag = 0x0;        //No Receive
    //2ms delay for each slave to report null message

    //Wait for null message to be received
    DCInit_transactions[6].Len = 4;
    DCInit_transactions[6].Data[0] = 0x01;
    DCInit_transactions[6].Data[1] = 0x0;
    DCInit_transactions[6].Data[2] = 0x0;
    DCInit_transactions[6].Data[3] = 0x0;
    DCInit_transactions[6].RxFlag = 0x1;        //Receive 0x10 or 0x12

    //Clear transmit buffer
    DCInit_transactions[7].Len = 4;
    DCInit_transactions[7].Data[0] = 0x20;
    DCInit_transactions[7].Data[1] = 0x0;
    DCInit_transactions[7].Data[2] = 0x0;
    DCInit_transactions[7].Data[3] = 0x0;
    DCInit_transactions[7].RxFlag = 0x0;        //No Receive

    //Clear receive buffer
    DCInit_transactions[8].Len = 4;
    DCInit_transactions[8].Data[0] = 0xe0;
    DCInit_transactions[8].Data[1] = 0x0;
    DCInit_transactions[8].Data[2] = 0x0;
    DCInit_transactions[8].Data[3] = 0x0;
    DCInit_transactions[8].RxFlag = 0x0;        //No Receive

}


/**
 * main.c
 */
int main(void)
{

    uint32_t i;
    WDTCTL = WDTPW | WDTHOLD;   // stop watchdog timer


    init_clock();
    init_gpio();                                    // Set up IO pins

    GPIO_setOutputHighOnPin(GPIO_PORT_P3, GPIO_PIN1);

    // Configure SPI Pins for UCA1CLK, UCA1TXD/UCA1SIMO and UCA1RXD/UCA1SOMI
    /*
    * Select Port 2
    * Set Pin 4, Pin 5 and Pin 6 to input Secondary Module Function
    */
    GPIO_setAsPeripheralModuleFunctionInputPin(
        GPIO_PORT_P2,
        GPIO_PIN4 + GPIO_PIN5 + GPIO_PIN6,
        GPIO_PRIMARY_MODULE_FUNCTION
    );

    // Set P1.0 to output direction

    GPIO_setAsOutputPin (GPIO_PORT_P1, GPIO_PIN0);
    GPIO_setAsInputPinWithPullUpResistor (GPIO_PORT_P4, GPIO_PIN2);
    GPIO_enableInterrupt (GPIO_PORT_P4, GPIO_PIN2);
    GPIO_selectInterruptEdge (GPIO_PORT_P4, GPIO_PIN2, GPIO_HIGH_TO_LOW_TRANSITION);
    GPIO_clearInterrupt (GPIO_PORT_P4, GPIO_PIN2);

    PMM_unlockLPM5();


    SetUpTransactions();
    TXData = 0x0;                             // Holds transaction number


    // Setup peripheral(s) now that gpio and clocks are setup
    init_spi_peripheral();                      // Init Maxim spi peripheral
    GPIO_setOutputLowOnPin(GPIO_PORT_P3, GPIO_PIN1);        //Maxim chip select low
    for(i=10000; i>0; i--);                                  //idle time between SPI transactions

        for(SPI_TX_index = 0; SPI_TX_index < DCInit_transactions[TXData].Len; SPI_TX_index++){
            while(!(UCA1IFG & UCTXIFG));
            UCA1TXBUF = DCInit_transactions[TXData].Data[SPI_TX_index];
            while (!(UCA1IFG & UCRXIFG));
               RXData = UCA1RXBUF;
        }
        TXData = 1;
        for(SPI_TX_index = 0; SPI_TX_index < DCInit_transactions[TXData].Len; SPI_TX_index++){
            while(!(UCA1IFG & UCTXIFG));
            UCA1TXBUF = DCInit_transactions[TXData].Data[SPI_TX_index];
            while (!(UCA1IFG & UCRXIFG));
            RXData = UCA1RXBUF;
        }
        TXData = 2;
        for(SPI_TX_index = 0; SPI_TX_index < DCInit_transactions[TXData].Len; SPI_TX_index++){
           while(!(UCA1IFG & UCTXIFG));
           UCA1TXBUF = DCInit_transactions[TXData].Data[SPI_TX_index];
           while (!(UCA1IFG & UCRXIFG));
           RXData = UCA1RXBUF;
        }
        TXData = 3;
        for(SPI_TX_index = 0; SPI_TX_index < DCInit_transactions[TXData].Len; SPI_TX_index++){
           while(!(UCA1IFG & UCTXIFG));
           UCA1TXBUF = DCInit_transactions[TXData].Data[SPI_TX_index];
           while (!(UCA1IFG & UCRXIFG));
           RXData = UCA1RXBUF;
        }

        __delay_cycles(64000);

        TXData = 4;
        for(SPI_TX_index = 0; SPI_TX_index < DCInit_transactions[TXData].Len; SPI_TX_index++){
           while(!(UCA1IFG & UCTXIFG));
           UCA1TXBUF = DCInit_transactions[TXData].Data[SPI_TX_index];
           while (!(UCA1IFG & UCRXIFG));
           RXData = UCA1RXBUF;
        }
        if ((TXData == 4) && (RXData == 0x21)){
            DCInit_transactions[TXData].RxFlag = 0;
            TXData = 5;
        }

//    GPIO_setOutputHighOnPin(GPIO_PORT_P3, GPIO_PIN1);        //Maxim chip select high
}

//******************************************************************************
//
//This is the PORT2_VECTOR interrupt vector service routine
//
//******************************************************************************
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=PORT4_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(PORT2_VECTOR)))
#endif
void P4_ISR (void)
{
 //   GPIO_setOutputHighOnPin(GPIO_PORT_P3, GPIO_PIN1);
    GPIO_clearInterrupt (GPIO_PORT_P4, GPIO_PIN2);
    // Toggle P1.0 output
    GPIO_toggleOutputOnPin (GPIO_PORT_P1, GPIO_PIN0);

    GPIO_disableInterrupt (GPIO_PORT_P4, GPIO_PIN2);
}


  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    此代码乍一看很好。  

    当(有意义的)数据由从器件发送时、从器件数据表中描述了这一点。 您使用的是什么从器件?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    是连接到菊花链中的两个 MAX17853芯片的 MAX17841芯片。 我正在尝试唤醒序列。 当 SPI 发送/接收是同步的时、这对 MOSI/ MISO 线路意味着什么? 例如、交易5后应作出响应。 响应字节的发生时间是否与事务5 (DCInit_事务[4])或之后的字节相同?

    如果没有预期的响应、我希望同时在示波器上看到 Tx 和 Rx 字节(同步 SPI)

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Tx 需要8位时间才能通过 MOSI 发送。 在此期间、SPI 同时在 MISO (Rx)位计时。 完成此操作后、将同时发生 Rx 完成事件(RXIFG)和 Tx 完成事件(与 TXIFG 相关、但与 TXIFG 不同)。 一旦从器件开始传输、您应该在示波器上同时看到 MISO 和 MOSI。

    当第一个字节通过 MOSI 发送时、从器件没有什么可说的、因为它不知道主器件需要什么、所以 MISO 没有什么意义。 这可以表示为0、1或高阻态(数据表将告诉您)。 在1个(或更多) Tx 字节之后、从器件有一个要说的内容、因此它驱动 MISO。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    看起来您在数据表 (19-6790;修订版3)表10中运行该序列。 当我读取事务5 (您的[4])时、状态字节(我们希望为0x21)将显示为第二个字节、而不是第四个字节。 说明意味着它可能不会立即为0x21、因此您必须不断询问。

    即使在此之前、我也希望在 MISO 上看到事务1 (您的[0])中第4个字节的0x05、因为它会读回刚刚写入的内容。

    如果您从未看到任何关于 MISO 的活动、这表明其他事情是错误的。 表10的文本提到了/SHDN。 该设置是否适当?

    您可能需要"开始小规模":构建一个 while (1)循环、该循环仅重复执行事务1 (可能在两者之间存在人为时间延迟)、直到获得一致的结果。

    ----------

    这可能是您的问题、也可能不是您的问题、但应该解决:

    >  param.clockPhase = 0;

    这将设置 UCCKPH=0。 数据表表2规定 CPHA=0、对应于 UCCKPH=1。 对于 driverlib、这将是:

    >  param.clockPhase = EUSCI_A_SPI_PHASE_DATA_Captured_ONFIRST_Changed_ON_NEXT;

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我想查看同时发生 Tx 和 Rx 的时序图。

    任意示例:TX 0xA 必须为响应获取 Rx 0x5。 在同一事务字节的时钟周期中、这两个字节是否都出现在 MOSI/ MISO 线路中? Rx 0xA 会发生什么情况?

    TX 0xB 无响应。 在同一字节的时钟周期中、Rx 0xB 是否会在 MOSI 和 MISO 线路上可见?

    我知道 Maxim 从站使用评估 GUI 进行正确响应。 我在他们的 GUI 中看不到任何 SHDN 设置。 我将看到我是否需要对该寄存器进行编程。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    数据表图1显示了 SPI 波形示例。 (唉,不是一个很好的--显示2个完整字节是否是那么困难?) "交叉切换"部分旨在表示"以不确定的值驱动"、即0或1、但不是 Hi-Z

    /SHDN 是一个引脚[参考数据表第7页]。 它为低电平有效、带有一个(非常弱)内部下拉电阻、所以如果它未连接、芯片被停止。 您需要将其驱动/拉高。 您是否有连接到此引脚的导线?

    [编辑:对于您的特定示例、您应该会看到与 MOSI=0x0A 和 MSO=配对的前8个 SCLK 。 第二个8个时钟将显示 MOSI= 并且 MISO = 0x05。]

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢您的回复和指导。 我连接了来自 MSP 430的 GPIO、并将其设置为 SHDL 的高电平。 连接到 MAX17841。 我还将 MAX17853的 SHDL 连接到了5V。 我将 MSP 430 SPI 信号连接到 EV 套件的连接器 J1。 我希望 MAX 17841能够在其 GPIO 上接收 SPI 信号。 我已附上 EV 套件原理图。 否则请告诉我。 我还更正了 SPI 时钟相位。 在 SPI 时钟之后的 MISO 线路上存在一些噪声。 在 SPI 事务期间它只是高电平。 我希望我可以连接到更简单的 SPI 外设、以查看 MSP430 SPI 接收的实际应用。 我对 sanity check.e2e.ti.com/.../MAX17841EVMINIQU.pdf 没有任何想法

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    如何为 MAX17841供电? 我假设您在 J1上为 DCIN 提供3.3V 电压、组装 JU1 (向 VAA 提供3.3V 电压)、并让 JU5保持开路? 您需要确保 SPI 以3.3V 的电压运行。

    我希望 MAX17853在隔离器的另一侧连接到 P1和 P2、因此我认为它们不会这样做。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我将 JU5设置为3.3V 设置。 我从 LP-MSP430上取一个3.3V 跳线、并将其插入 MAX17841的 DCIN 测试点。 SHDL、CS'、SCLK、MOSI、MISO 都连接到接头 J1。 我还将 LP 的3.3V 电压跳线连接到两个 MAX17853评估板的 SHDL 引脚。 MAX17841的 J1接头上的 VAA 和 DCIN 均为3.3V。 MAX17853上的 SHNL 测量3.3V。  我在 MISO 引脚上看到一个由高电平到低电平的转换、我假设当 SHDL 被 MSP430置为高电平时。 接下来、我会看到所有的 MOSI 字节、但只会看到像 MISO 上的纹波这样的噪声、该噪声保持在高电平。  

    仅一个引脚上的分流器位置相当于插头保持断开(MAX17841 EV 套件的表1)。

    谢谢

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    在多次阅读了关于"寄存器事务"的部分[DS p.9]之后、我现在将其解释为:每个事务(由/CS assert-de-assert 计时)都是基于第一个字节的读取或写入。 您的事务[0]是对寄存器0x10、0x12、0x14的写操作、而不是对寄存器0x10的写操作和读操作(-back)。 这意味着:

    1)将事务[0]分成两个:第一个(写)为0x10、0x05、第二个(读回)为0x11、0x00。

    2) 2)对于由此产生的两个事务中的每一个、在之前声明/CS (低电平) 、在之后取消声明它。

    3) 3)对其他交易重复(视情况而定)。

    --------

    Tstartup [DS p.4]、从/SHDN 高电平到真正有效、最长可达2ms。 在将/SHDN 设置为高电平和启动第一个事务之间插入类似"__delay_cycles (2000);"[假设 MCLK=1MHz]的内容可能是谨慎的。 (我不建议将 for ()循环作为延迟、因为很难知道编译器将如何处理它。)

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    这很有用!! 非常感谢。 我写了一个成功的字,然后读了一个宝贵的字。