Files
rpi_pico_mfrc522/third_party/mfrc522_integration/mfrc522_rp2040_integration.c
Stefan Kratochwil 561b6d7ff7 Probably (!) fixed problem with spurious interrupts.
After turning on the analog section of the mfrc522, a lot of spurious
interrupts could be observed. Debugging revealed that the mfrc522 did not
give consistent information about an interrupt source.

A closer look into the chip documentation (chapter 9.3.1.4) revealed that
the interrupt pin is open drain by default, but can be set to CMOS.

Switched to CMOS, deactivated internal and external pull down resistors.
No more spurious interrupts.
2024-05-31 15:20:11 +02:00

468 lines
12 KiB
C

/**
* Copyright (c) 2015 - present LibDriver All rights reserved
*
* The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @file driver_mfrc522_interface_template.c
* @brief driver mfrc522 interface template source file
* @version 1.0.0
* @author Shifeng Li
* @date 2022-05-31
*
* <h3>history</h3>
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022/05/31 <td>1.0 <td>Shifeng Li <td>first upload
* </table>
*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/spi.h"
#include "hardware/sync.h"
#ifndef NO_DEBUG
#include <stdarg.h>
#endif
#include "driver_mfrc522_interface.h"
#define MFRC522_CFG_RST_GPIO 9
#define MFRC522_CFG_SPI_INSTANCE spi1
#define MFRC522_CFG_SPI_MISO_GPIO 12
#define MFRC522_CFG_SPI_MOSI_GPIO 11
#define MFRC522_CFG_SPI_CLK_GPIO 10
#define MFRC522_CFG_SPI_SS_GPIO 13
#define MFRC522_CFG_SPI_SPEED_MHZ (1000 * 1000)
static inline void print_hex(uint8_t *bytes, size_t len)
{
for (size_t idx = 0; idx < len; ++idx) {
mfrc522_interface_debug_print("%x", bytes[idx]);
}
mfrc522_interface_debug_print("\n");
}
static uint32_t irq_status = 0;
/**
* @brief Helper function to pull the CS line low
*
* Taken from pico-examples, bme280_spi.c
*/
static inline void cs_select() {
// irq_status = save_and_disable_interrupts();
asm volatile("nop \n nop \n nop");
gpio_put(MFRC522_CFG_SPI_SS_GPIO, 0); // Active low
asm volatile("nop \n nop \n nop");
}
/**
* @brief Helper function to release the CS line low
*
* Taken from pico-examples, bme280_spi.c
*/
static inline void cs_deselect() {
asm volatile("nop \n nop \n nop");
gpio_put(MFRC522_CFG_SPI_SS_GPIO, 1);
asm volatile("nop \n nop \n nop");
// restore_interrupts(irq_status);
}
/**
* @brief interface reset gpio init
* @return status code
* - 0 success
* - 1 reset gpio init failed
* @note none
*/
uint8_t mfrc522_interface_reset_gpio_init(void)
{
gpio_init(MFRC522_CFG_RST_GPIO);
gpio_set_dir(MFRC522_CFG_RST_GPIO, GPIO_OUT);
return 0;
}
/**
* @brief interface reset gpio deinit
* @return status code
* - 0 success
* - 1 reset gpio deinit failed
* @note none
*/
uint8_t mfrc522_interface_reset_gpio_deinit(void)
{
gpio_deinit(MFRC522_CFG_RST_GPIO);
return 0;
}
/**
* @brief interface reset gpio write
* @param[in] value is the written value
* @return status code
* - 0 success
* - 1 reset gpio write failed
* @note none
*/
uint8_t mfrc522_interface_reset_gpio_write(uint8_t value)
{
gpio_put(MFRC522_CFG_RST_GPIO, !!value);
return 0;
}
/**
* @brief interface iic bus init
* @return status code
* - 0 success
* - 1 iic init failed
* @note none
*/
uint8_t mfrc522_interface_iic_init(void)
{
mfrc522_interface_debug_print("WARN: %s not implemented!\n", __FUNCTION__);
return 0;
}
/**
* @brief interface iic bus deinit
* @return status code
* - 0 success
* - 1 iic deinit failed
* @note none
*/
uint8_t mfrc522_interface_iic_deinit(void)
{
mfrc522_interface_debug_print("WARN: %s not implemented!\n", __FUNCTION__);
return 0;
}
/**
* @brief interface iic bus read
* @param[in] addr is the iic device write address
* @param[in] reg is the iic register address
* @param[out] *buf points to a data buffer
* @param[in] len is the length of the data buffer
* @return status code
* - 0 success
* - 1 read failed
* @note none
*/
uint8_t mfrc522_interface_iic_read(uint8_t addr, uint8_t reg, uint8_t *buf, uint16_t len)
{
mfrc522_interface_debug_print("WARN: %s not implemented!\n", __FUNCTION__);
return 0;
}
/**
* @brief interface iic bus write
* @param[in] addr is the iic device write address
* @param[in] reg is the iic register address
* @param[in] *buf points to a data buffer
* @param[in] len is the length of the data buffer
* @return status code
* - 0 success
* - 1 write failed
* @note none
*/
uint8_t mfrc522_interface_iic_write(uint8_t addr, uint8_t reg, uint8_t *buf, uint16_t len)
{
mfrc522_interface_debug_print("WARN: %s not implemented!\n", __FUNCTION__);
return 0;
}
/**
* @brief interface spi bus init
* @return status code
* - 0 success
* - 1 spi init failed
* @note none
*/
uint8_t mfrc522_interface_spi_init(void)
{
gpio_set_function(MFRC522_CFG_SPI_MISO_GPIO, GPIO_FUNC_SPI);
gpio_set_function(MFRC522_CFG_SPI_MOSI_GPIO, GPIO_FUNC_SPI);
gpio_set_function(MFRC522_CFG_SPI_CLK_GPIO, GPIO_FUNC_SPI);
//gpio_set_function(MFRC522_CFG_SPI_SS_GPIO, GPIO_FUNC_SPI);
//gpio_set_dir(MFRC522_CFG_SPI_CLK_GPIO, GPIO_OUT);
gpio_init(MFRC522_CFG_SPI_SS_GPIO);
gpio_set_dir(MFRC522_CFG_SPI_SS_GPIO, GPIO_OUT);
gpio_put(MFRC522_CFG_SPI_SS_GPIO, 1);
/*
* From the manual:
* "There is no guarantee that the baudrate requested can be achieved exactly;
* the nearest will be chosen and returned"
*/
return !spi_init(MFRC522_CFG_SPI_INSTANCE, MFRC522_CFG_SPI_SPEED_MHZ);
}
/**
* @brief interface spi bus deinit
* @return status code
* - 0 success
* - 1 spi deinit failed
* @note none
*/
uint8_t mfrc522_interface_spi_deinit(void)
{
mfrc522_interface_debug_print("WARN: %s not implemented!\n", __FUNCTION__);
return 0;
}
/**
* @brief interface spi bus read
* @param[in] reg is the register address
* @param[out] *buf points to a data buffer
* @param[in] len is the length of data buffer
* @return status code
* - 0 success
* - 1 read failed
* @note none
*/
uint8_t mfrc522_interface_spi_read(uint8_t reg, uint8_t *buf, uint16_t len)
{
if (len == UINT16_MAX)
return 1;
// We need to read len + 1 bytes...
const size_t local_buf_len = len + 1;
uint8_t local_buf[local_buf_len];
memset(local_buf, 0, local_buf_len);
cs_select();
uint16_t n_bytes_read = spi_read_blocking(MFRC522_CFG_SPI_INSTANCE, reg, local_buf, local_buf_len);
cs_deselect();
// ...and ignore the first byte we received.
memcpy(buf, local_buf + 1, len);
// XXX Debug - remove me
mfrc522_interface_debug_print("[SPI-RX]: ");
print_hex(buf, len);
return (uint8_t) (n_bytes_read == local_buf_len) ? 0 : 1;
}
/**
* @brief interface spi bus write
* @param[in] reg is the register address
* @param[in] *buf points to a data buffer
* @param[in] len is the length of data buffer
* @return status code
* - 0 success
* - 1 write failed
* @note none
*/
uint8_t mfrc522_interface_spi_write(uint8_t reg, uint8_t *buf, uint16_t len)
{
if (len == UINT16_MAX)
return 1;
// We need to send the address byte (reg) as part of the payload.
const size_t local_buf_len = len + 1;
uint8_t local_buf[local_buf_len];
local_buf[0] = reg;
memcpy(&local_buf[1], buf, len);
// XXX Debug - remove me
mfrc522_interface_debug_print("[SPI-TX]: ");
print_hex(buf, len);
cs_select();
uint16_t n_bytes_written = spi_write_blocking(MFRC522_CFG_SPI_INSTANCE, local_buf, local_buf_len);
cs_deselect();
return (uint8_t) (n_bytes_written == local_buf_len) ? 0 : 1;
}
/**
* @brief interface uart init
* @return status code
* - 0 success
* - 1 uart init failed
* @note none
*/
uint8_t mfrc522_interface_uart_init(void)
{
mfrc522_interface_debug_print("WARN: %s not implemented!\n", __FUNCTION__);
return 0;
}
/**
* @brief interface uart deinit
* @return status code
* - 0 success
* - 1 uart deinit failed
* @note none
*/
uint8_t mfrc522_interface_uart_deinit(void)
{
mfrc522_interface_debug_print("WARN: %s not implemented!\n", __FUNCTION__);
return 0;
}
/**
* @brief interface uart read
* @param[out] *buf points to a data buffer
* @param[in] len is the length of the data buffer
* @return status code
* - 0 success
* - 1 read failed
* @note none
*/
uint16_t mfrc522_interface_uart_read(uint8_t *buf, uint16_t len)
{
mfrc522_interface_debug_print("WARN: %s not implemented!\n", __FUNCTION__);
return 0;
}
/**
* @brief interface uart write
* @param[in] *buf points to a data buffer
* @param[in] len is the length of the data buffer
* @return status code
* - 0 success
* - 1 write failed
* @note none
*/
uint8_t mfrc522_interface_uart_write(uint8_t *buf, uint16_t len)
{
mfrc522_interface_debug_print("WARN: %s not implemented!\n", __FUNCTION__);
return 0;
}
/**
* @brief interface uart flush
* @return status code
* - 0 success
* - 1 uart flush failed
* @note none
*/
uint8_t mfrc522_interface_uart_flush(void)
{
mfrc522_interface_debug_print("WARN: %s not implemented!\n", __FUNCTION__);
return 0;
}
/**
* @brief interface delay ms
* @param[in] ms
* @note none
*/
void mfrc522_interface_delay_ms(uint32_t ms)
{
sleep_ms(ms);
}
/**
* @brief interface print format data
* @param[in] fmt is the format data
* @note none
*/
void mfrc522_interface_debug_print(const char *const fmt, ...)
{
#ifndef NO_DEBUG
char str[256];
uint16_t len;
va_list args;
memset((char *)str, 0, sizeof(char) * 256);
va_start(args, fmt);
vsnprintf((char *)str, 255, (char const *)fmt, args);
va_end(args);
len = strlen((char *)str);
(void)printf((uint8_t *)str, len);
#endif
}
/**
* @brief interface receive callback
* @param[in] type is the irq type
* @note none
*/
void mfrc522_interface_receive_callback(uint16_t type)
{
switch (type)
{
case MFRC522_INTERRUPT_MFIN_ACT :
{
mfrc522_interface_debug_print("mfrc522: irq mfin act.\n");
break;
}
case MFRC522_INTERRUPT_CRC :
{
mfrc522_interface_debug_print("mfrc522: irq crc.\n");
break;
}
case MFRC522_INTERRUPT_TX :
{
mfrc522_interface_debug_print("mfrc522: irq tx.\n");
break;
}
case MFRC522_INTERRUPT_RX :
{
mfrc522_interface_debug_print("mfrc522: irq rx.\n");
break;
}
case MFRC522_INTERRUPT_IDLE :
{
mfrc522_interface_debug_print("mfrc522: irq idle.\n");
break;
}
case MFRC522_INTERRUPT_HI_ALERT :
{
mfrc522_interface_debug_print("mfrc522: irq hi alert.\n");
break;
}
case MFRC522_INTERRUPT_LO_ALERT :
{
mfrc522_interface_debug_print("mfrc522: irq lo alert.\n");
break;
}
case MFRC522_INTERRUPT_ERR :
{
mfrc522_interface_debug_print("mfrc522: irq err.\n");
break;
}
case MFRC522_INTERRUPT_TIMER :
{
mfrc522_interface_debug_print("mfrc522: irq timer.\n");
break;
}
default :
{
mfrc522_interface_debug_print("mfrc522: irq unknown code.\n");
break;
}
}
}