Using ATSAMC21 as an I2C Slave

Get the demo source code file at the end of the article ↓Software Platform: MCC v5.5.2, MPLAB X IDE v6.25Hardware:ATSAMC21J18AUsing MPLAB-Harmony Configuration ToolSet the system clock to 48MHzUsing ATSAMC21 as an I2C SlaveSet the corresponding option bits in the clock tree to make the CPU clock 48MHzUsing ATSAMC21 as an I2C SlaveOpen the pin configuration interfaceUsing ATSAMC21 as an I2C SlaveUART Pin and Function Parameter SettingsRefer toSAM C21 Xplained Prodevelopment board manual for serial port pinsUsing ATSAMC21 as an I2C SlaveSet the serial port IO in the Harmony configuration toolUsing ATSAMC21 as an I2C SlaveAdd SERCOM4 resource in the resource list and set it to UART functionUsing ATSAMC21 as an I2C SlaveSet serial port parametersUsing ATSAMC21 as an I2C SlaveAdd SERCOM2, configure it as an I2C slave and set its parametersUsing ATSAMC21 as an I2C SlaveI2C Pin and Function Parameter SettingsRefer toSAM C21 Xplained Prodevelopment board manual for I2C pinsUsing ATSAMC21 as an I2C SlaveSet I2C slave IO portsUsing ATSAMC21 as an I2C SlaveSet the names of the IO ports for UART and I2CUsing ATSAMC21 as an I2C SlaveAdd a timer, set the timer interval to 500msUsing ATSAMC21 as an I2C SlaveHarmony Interrupt SettingsUsing ATSAMC21 as an I2C SlaveUsing ATSAMC21 as an I2C SlaveRefer toSAM C21 Xplained Prodevelopment board manual for LED pinsUsing ATSAMC21 as an I2C SlaveSet the IO port for the LEDUsing ATSAMC21 as an I2C SlaveCode WritingRegister the timer callback functionUsing ATSAMC21 as an I2C SlaveIn thetimercallback function, add the LED toggle codeUsing ATSAMC21 as an I2C SlaveI2C Slave AddressUsing ATSAMC21 as an I2C SlaveRefer to the I2C interrupt section in the manual to understand the available I2C interrupts for subsequent use of interrupt callback functions.Using ATSAMC21 as an I2C SlaveI2C Interrupt Service Function

void __attribute__((used)) SERCOM2_I2C_InterruptHandler(void){    uint32_t intFlags = SERCOM2_REGS->I2CS.SERCOM_INTFLAG;    SERCOM_I2C_SLAVE_TRANSFER_EVENT event = SERCOM_I2C_SLAVE_TRANSFER_EVENT_NONE;
    if((intFlags & SERCOM2_REGS->I2CS.SERCOM_INTENSET) != 0U)    {        uintptr_t context = sercom2I2CSObj.context;
        if ((intFlags & SERCOM_I2CS_INTFLAG_ERROR_Msk) != 0U)        {            event = SERCOM_I2C_SLAVE_TRANSFER_EVENT_ERROR;
            if (sercom2I2CSObj.callback != NULL)            {                (void)sercom2I2CSObj.callback(event, context);            }        }        if ((intFlags & SERCOM_I2CS_INTFLAG_AMATCH_Msk) != 0U)        {            sercom2I2CSObj.isBusy = true;
            sercom2I2CSObj.isFirstRxAfterAddressPending = true;
            sercom2I2CSObj.isRepeatedStart = ((SERCOM2_REGS->I2CS.SERCOM_STATUS & SERCOM_I2CS_STATUS_SR_Msk)  != 0U) ? true : false;
            event = SERCOM_I2C_SLAVE_TRANSFER_EVENT_ADDR_MATCH;        }
// DRDY is the data ready flag, indicating that the data to be received or sent via I2C is ready        if ((intFlags & SERCOM_I2CS_INTFLAG_DRDY_Msk) != 0U)        {            if (SERCOM2_I2C_TransferDirGet() == SERCOM_I2C_SLAVE_TRANSFER_DIR_WRITE)            {                event = SERCOM_I2C_SLAVE_TRANSFER_EVENT_RX_READY;            }            else            {                if ((sercom2I2CSObj.isFirstRxAfterAddressPending == true) || (SERCOM2_I2C_LastByteAckStatusGet() == SERCOM_I2C_SLAVE_ACK_STATUS_RECEIVED_ACK))                {                    sercom2I2CSObj.isFirstRxAfterAddressPending = false;
                    event = SERCOM_I2C_SLAVE_TRANSFER_EVENT_TX_READY;                }            }        }        if ((intFlags & SERCOM_I2CS_INTFLAG_PREC_Msk) != 0U)        {            sercom2I2CSObj.isBusy = false;
            event = SERCOM_I2C_SLAVE_TRANSFER_EVENT_STOP_BIT_RECEIVED;        }// Here, start using the callback function to handle subsequent tasks. Through the event parameter of the callback function, you can know// the current state. If the event is SERCOM_I2C_SLAVE_TRANSFER_EVENT_RX_READY// it is in receive state, if the event is SERCOM_I2C_SLAVE_TRANSFER_EVENT_TX_READY// it is in send state.        if (sercom2I2CSObj.callback != NULL)        {            (void)sercom2I2CSObj.callback(event, context);        }    }    SERCOM2_REGS->I2CS.SERCOM_INTFLAG = (uint8_t)intFlags;}

It is necessary to register the callback function, and then in the callback function, check the event status, and handle the corresponding tasks based on the event status.

// Register callback functionSERCOM2_I2C_CallbackRegister(&SERCOM_I2C_SLAVE_CALLBACK_ADCRES,(uintptr_t)(0));
static bool SERCOM_I2C_SLAVE_CALLBACK_ADCRES ( SERCOM_I2C_SLAVE_TRANSFER_EVENT event, uintptr_t contextHandle ){    // I2C SLAVE Read    if(event == SERCOM_I2C_SLAVE_TRANSFER_EVENT_RX_READY)    {        adc_testStruct.adcValue_res = SERCOM2_I2C_ReadByte();        adc_testStruct.print_flag = 1;
        SERCOM4_USART_Write("1",1);
        return true;
    }
    // I2C SLAVE Write    else if(event == SERCOM_I2C_SLAVE_TRANSFER_EVENT_TX_READY)    {
        SERCOM4_USART_Write("2",1);
        return true;
    }
    return false;}

In the interrupt function, variables must be modified using the volatile keyword, otherwise the variable values will not update!I2C Slave TestingUseMCP2221 I2C Host (I2C Master) to test the I2C SlaveUsing ATSAMC21 as an I2C SlaveUse theEDBGvirtual serial port on the development boardUsing ATSAMC21 as an I2C SlaveSet the EDBG virtual serial port in the serial port assistant, enabling the DTR bitUsing ATSAMC21 as an I2C SlaveAboutuintptr_t type descriptionOn 64-bit machines, intptr_t and uintptr_t are aliases for long int and unsigned long int; on 32-bit machines, intptr_t and uintptr_t are aliases for int and unsigned int.

Link: https://pan.baidu.com/s/1Gas4RUq5wO3JE2TwDXyfcA

Note: Reply with the keyword “汤圆说电子” to get the extraction code for SAMC21-I2C-SLAVE,Get the extraction codeUsing ATSAMC21 as an I2C SlaveUsing ATSAMC21 as an I2C SlaveUsing ATSAMC21 as an I2C Slave

Leave a Comment