返回列表 发新帖我要提问本帖赏金: 30.00元(功能说明)

[麦麦茶水间] 【每周分享】以IS3980S为例,分享一种多板多芯片且引脚复用的驱动代码实现和应用方法

[复制链接]
10865|3
dffzh 发表于 2026-6-9 18:36 | 显示全部楼层 |阅读模式
#申请原创# #技术资源#

大家直接看标题可能有点疑惑,所以我这里先解释一下,所谓的“多板多芯片且引脚复用”其实是这个意思:
就是一个产品有多个PCB板,每个板子上都有两个及以上的同样的芯片;且由于MCU引脚资源有限的问题会共用GPIO引脚以实现分时复用。
以我以前接触过的产品为例,上面有两块PCB板,一块带MCU芯片的CPU板,上面有两颗IS3980S芯片;一块带输入检测的IO板,上面也有两颗IS3980S芯片,且两块PCB板通过连接线束连接,主要是将IO板上的IS3980S芯片检测到的输入数据通过总线回传到MCU。
另外,由于MCU引脚资源有限,PCB板上的两颗IS3980S芯片的SCLK、MISO和MOSI三根信号线是共用一组GPIO引脚的,各自通过NSS片选信号进行数据读取的切换,其实就是类似于SPI的一主多从拓扑;同样的,IO板上的两颗IS3980S芯片的SCLK、MISO和MOSI三根信号线是共用另外一组GPIO引脚的,各自通过NSS片选信号进行数据读取的切换。
其实说了半天,其通过下面的框图基本上就可以知道是什么硬件拓扑了,更一目了然:
这里的IS3980S其实是一款支持8通道隔离式数字输入检测的接收器芯片,走的是四线串行总线接口,即MCU端可以用硬件SPI或者模拟SPI来实现数据读取。另外,IS3980S其实也支持菊花链连接,但是我们考虑到应用场景的抗干扰性能和数据稳定性,我们没有采用这种方式,而是采用了通过NSS片选信号进行分时复用读取数据的方式:
那对于类似我们这样的硬件设计,软件的驱动代码应该怎么实现比较好呢?首先的原则当然是驱动代码的各个函数接口尽量保证只有一个。鉴于此,我是按照下面这种方式实现的:
在原始的驱动代码的各个函数接口的形参里面加入所谓索引index的概念,比如既然有两块PCB,那就加个PCB索引pcb_index来识别是CPU板还是IO板;既然有两个芯片来复用同一组IO引脚,其实本质上是两个NSS片选信号,那就加个NSS索引nss_index来识别是哪个芯片处于激活active状态,哪个芯片处于非工作状态。

然后可以定义几个宏,比如各个板子的芯片的最大个数是2,然后需要区分是CPU板还是IO板的芯片,这个是对应pcb_index的,;识别PCB板类型后还要进一步区分是哪个芯片,这个是对应nss_index的,得到相关的宏定义如下:
  1. //pcb_index
  2. #define IS3980S_MAX (2)
  3. #define CPU_IS3980S (0)
  4. #define KEY_IS3980S (1)
  5. //nss_index
  6. #define  IS3980S_NSS_MAX    2
  7. #define  CPU_IS3980S_NSS1   0
  8. #define  CPU_IS3980S_NSS2   1
  9. #define  KEY_IS3980S_NSS1   0
  10. #define  KEY_IS3980S_NSS2   1
然后对于SCLK、MOSI、MISO和NSS信号绑定MCU的GPIO引脚,毫无疑问是通过宏定义来完成,并以PCB板名称来作为前缀以识别,比如对于NSS引脚,可以参考如下定义:
  1. #define  CPU_IS3980S_NSS1_GPIO   GPIOB
  2. #define  CPU_IS3980S_NSS2_GPIO   GPIOB
  3. #define  CPU_IS3980S_NSS1_PIN         GPIO_PINS_6
  4. #define  CPU_IS3980S_NSS2_PIN         GPIO_PINS_1

  5. #define  KEY_IS3980S_NSS1_GPIO   GPIOA
  6. #define  KEY_IS3980S_NSS2_GPIO   GPIOA
  7. #define  KEY_IS3980S_NSS1_PIN         GPIO_PINS_9
  8. #define  KEY_IS3980S_NSS2_PIN         GPIO_PINS_10
这里有个建议,即使一组串行信号连接在同一个GPIO组,定义的时候也要单独分开,以增强代码扩展性和维护性。

接着就可以通过宏定义的方式并结合GPIO引脚及pcb_index和nss_index参数来实现引脚分时切换的代码,比如对于NSS、SCLK(MOSI类似)和MISO,可以实现如下:
  1. #define IS3980S_NSS_HIGH(pcb_index, nss_index) \
  2.         do{ \
  3.         switch(pcb_index) \
  4.         { \
  5.             case CPU_IS3980S: \
  6.                                 { \
  7.                                     switch(nss_index) \
  8.                                         { \
  9.                         case CPU_IS3980S_NSS1: \
  10.                                         gpio_bits_write(CPU_IS3980S_NSS1_GPIO, CPU_IS3980S_NSS1_PIN, TRUE); \
  11.                                     break; \
  12.                                     case CPU_IS3980S_NSS2: \
  13.                                         gpio_bits_write(CPU_IS3980S_NSS2_GPIO, CPU_IS3980S_NSS2_PIN, TRUE); \
  14.                                         break; \
  15.                                     default:   \
  16.                                         break; \
  17.                     }\
  18.                     }\
  19.                             break; \
  20.                         case KEY_IS3980S: \
  21.                                 { \
  22.                                     switch(nss_index) \
  23.                                         { \
  24.                         case KEY_IS3980S_NSS1: \
  25.                                         gpio_bits_write(KEY_IS3980S_NSS1_GPIO, KEY_IS3980S_NSS1_PIN, TRUE); \
  26.                                     break; \
  27.                                     case KEY_IS3980S_NSS2: \
  28.                                         gpio_bits_write(KEY_IS3980S_NSS2_GPIO, KEY_IS3980S_NSS2_PIN, TRUE); \
  29.                                         break; \
  30.                                     default:   \
  31.                                         break; \
  32.                     }\
  33.                     }\
  34.                                 break; \
  35.                         default:   \
  36.                                 break; \
  37.         }\
  38.         }while(0);

  39. #define IS3980S_SCK_HIGH(pcb_index) \
  40.         do{ \
  41.         switch(pcb_index) \
  42.         { \
  43.             case CPU_IS3980S: \
  44.                                 gpio_bits_write(CPU_IS3980S_SCK_GPIO, CPU_IS3980S_SCK_PIN, TRUE); \
  45.                             break; \
  46.                         case KEY_IS3980S: \
  47.                                 gpio_bits_write(KEY_IS3980S_SCK_GPIO, KEY_IS3980S_SCK_PIN, TRUE); \
  48.                                 break; \
  49.                         default:   \
  50.                                 break; \
  51.         }\
  52.         }while(0);

  53. #define IS3980S_READ_MISO_CPU()  gpio_input_data_bit_read(CPU_IS3980S_MISO_GPIO, CPU_IS3980S_MISO_PIN)
  54. #define IS3980S_READ_MISO_KEY()  gpio_input_data_bit_read(KEY_IS3980S_MISO_GPIO, KEY_IS3980S_MISO_PIN)
然后对于这种上电时候需要通过MCU对其进行初始化配置的芯片,这种实现方法以芯片最大个数为for循环的条件即可调用一次初始化接口就能完成芯片初始化,如下所示:
  1. void is3980s_all_init(void)
  2. {
  3.     uint8_t i = 0;
  4.         uint8_t j = 0;

  5.         for(i=0; i<IS3980S_MAX; i++)
  6.         {
  7.             for(j=0; j<IS3980S_NSS_MAX; j++)
  8.             {
  9.                 is3980s_init(i, j);
  10.             }
  11.         }
  12. }
下面就与大家展示一下这个IS3980S芯片的多板多芯片且引脚复用的驱动代码:

头文件如下所示:
  1. #ifndef __IS3980S_H__
  2. #define __IS3980S_H__

  3. /*SPI data frame length (byte)*/
  4. #define IS3980S_SPI_DATA_LEN  3

  5. /*hardware interface*/
  6. #define IS3980S_MAX (2)
  7. #define CPU_IS3980S (0)
  8. #define KEY_IS3980S (1)

  9. #define  IS3980S_NSS_MAX    2
  10. #define  CPU_IS3980S_NSS1   0
  11. #define  CPU_IS3980S_NSS2   1
  12. #define  KEY_IS3980S_NSS1   0
  13. #define  KEY_IS3980S_NSS2   1

  14. #define  CPU_IS3980S_GPIO            GPIOB
  15. #define  CPU_IS3980S_SCK_GPIO    GPIOB
  16. #define  CPU_IS3980S_MOSI_GPIO   GPIOB
  17. #define  CPU_IS3980S_MISO_GPIO   GPIOB
  18. #define  CPU_IS3980S_NSS1_GPIO   GPIOB
  19. #define  CPU_IS3980S_NSS2_GPIO   GPIOB

  20. #define  CPU_IS3980S_SCK_PIN         GPIO_PINS_7
  21. #define  CPU_IS3980S_MOSI_PIN         GPIO_PINS_9
  22. #define  CPU_IS3980S_MISO_PIN         GPIO_PINS_8
  23. #define  CPU_IS3980S_NSS1_PIN         GPIO_PINS_6
  24. #define  CPU_IS3980S_NSS2_PIN         GPIO_PINS_1

  25. #define  KEY_IS3980S_GPIO            GPIOB
  26. #define  KEY_IS3980S_SCK_GPIO    GPIOB
  27. #define  KEY_IS3980S_MOSI_GPIO   GPIOB
  28. #define  KEY_IS3980S_MISO_GPIO   GPIOB
  29. #define  KEY_IS3980S_NSS1_GPIO   GPIOA
  30. #define  KEY_IS3980S_NSS2_GPIO   GPIOA

  31. #define  KEY_IS3980S_SCK_PIN         GPIO_PINS_3
  32. #define  KEY_IS3980S_MOSI_PIN         GPIO_PINS_5
  33. #define  KEY_IS3980S_MISO_PIN         GPIO_PINS_4
  34. #define  KEY_IS3980S_NSS1_PIN         GPIO_PINS_9
  35. #define  KEY_IS3980S_NSS2_PIN         GPIO_PINS_10


  36. #define IS3980S_NSS_HIGH(pcb_index, nss_index) \
  37.         do{ \
  38.         switch(pcb_index) \
  39.         { \
  40.             case CPU_IS3980S: \
  41.                                 { \
  42.                                     switch(nss_index) \
  43.                                         { \
  44.                         case CPU_IS3980S_NSS1: \
  45.                                         gpio_bits_write(CPU_IS3980S_NSS1_GPIO, CPU_IS3980S_NSS1_PIN, TRUE); \
  46.                                     break; \
  47.                                     case CPU_IS3980S_NSS2: \
  48.                                         gpio_bits_write(CPU_IS3980S_NSS2_GPIO, CPU_IS3980S_NSS2_PIN, TRUE); \
  49.                                         break; \
  50.                                     default:   \
  51.                                         break; \
  52.                     }\
  53.                     }\
  54.                             break; \
  55.                         case KEY_IS3980S: \
  56.                                 { \
  57.                                     switch(nss_index) \
  58.                                         { \
  59.                         case KEY_IS3980S_NSS1: \
  60.                                         gpio_bits_write(KEY_IS3980S_NSS1_GPIO, KEY_IS3980S_NSS1_PIN, TRUE); \
  61.                                     break; \
  62.                                     case KEY_IS3980S_NSS2: \
  63.                                         gpio_bits_write(KEY_IS3980S_NSS2_GPIO, KEY_IS3980S_NSS2_PIN, TRUE); \
  64.                                         break; \
  65.                                     default:   \
  66.                                         break; \
  67.                     }\
  68.                     }\
  69.                                 break; \
  70.                         default:   \
  71.                                 break; \
  72.         }\
  73.         }while(0);


  74. #define IS3980S_NSS_LOW(pcb_index, nss_index) \
  75.         do{ \
  76.         switch(pcb_index) \
  77.         { \
  78.             case CPU_IS3980S: \
  79.                                 { \
  80.                                     switch(nss_index) \
  81.                                         { \
  82.                         case CPU_IS3980S_NSS1: \
  83.                                             gpio_bits_write(CPU_IS3980S_NSS1_GPIO, CPU_IS3980S_NSS1_PIN, FALSE); \
  84.                                         break; \
  85.                                     case CPU_IS3980S_NSS2: \
  86.                                             gpio_bits_write(CPU_IS3980S_NSS2_GPIO, CPU_IS3980S_NSS2_PIN, FALSE); \
  87.                                             break; \
  88.                                     default:   \
  89.                                             break; \
  90.                     }\
  91.                     }\
  92.                             break; \
  93.                         case KEY_IS3980S: \
  94.                                 { \
  95.                                     switch(nss_index) \
  96.                                         { \
  97.                         case KEY_IS3980S_NSS1: \
  98.                                             gpio_bits_write(KEY_IS3980S_NSS1_GPIO, KEY_IS3980S_NSS1_PIN, FALSE); \
  99.                                         break; \
  100.                                     case KEY_IS3980S_NSS2: \
  101.                                             gpio_bits_write(KEY_IS3980S_NSS2_GPIO, KEY_IS3980S_NSS2_PIN, FALSE); \
  102.                                             break; \
  103.                                     default:   \
  104.                                             break; \
  105.                     }\
  106.                     }\
  107.                                 break; \
  108.                         default:   \
  109.                                 break; \
  110.         }\
  111.         }while(0);

  112. #define IS3980S_SCK_HIGH(pcb_index) \
  113.         do{ \
  114.         switch(pcb_index) \
  115.         { \
  116.             case CPU_IS3980S: \
  117.                                 gpio_bits_write(CPU_IS3980S_SCK_GPIO, CPU_IS3980S_SCK_PIN, TRUE); \
  118.                             break; \
  119.                         case KEY_IS3980S: \
  120.                                 gpio_bits_write(KEY_IS3980S_SCK_GPIO, KEY_IS3980S_SCK_PIN, TRUE); \
  121.                                 break; \
  122.                         default:   \
  123.                                 break; \
  124.         }\
  125.         }while(0);

  126. #define IS3980S_SCK_LOW(pcb_index) \
  127.         do{ \
  128.         switch(pcb_index) \
  129.         { \
  130.             case CPU_IS3980S: \
  131.                                 gpio_bits_write(CPU_IS3980S_SCK_GPIO, CPU_IS3980S_SCK_PIN, FALSE); \
  132.                             break; \
  133.                         case KEY_IS3980S: \
  134.                                 gpio_bits_write(KEY_IS3980S_SCK_GPIO, KEY_IS3980S_SCK_PIN, FALSE); \
  135.                                 break; \
  136.                         default:   \
  137.                                 break; \
  138.         }\
  139.         }while(0);


  140. #define IS3980S_MOSI_HIGH(pcb_index) \
  141.         do{ \
  142.         switch(pcb_index) \
  143.         { \
  144.             case CPU_IS3980S: \
  145.                                 gpio_bits_write(CPU_IS3980S_MOSI_GPIO, CPU_IS3980S_MOSI_PIN, TRUE); \
  146.                             break; \
  147.                         case KEY_IS3980S: \
  148.                                 gpio_bits_write(KEY_IS3980S_MOSI_GPIO, KEY_IS3980S_MOSI_PIN, TRUE); \
  149.                                 break; \
  150.                         default:   \
  151.                                 break; \
  152.         }\
  153.         }while(0);

  154. #define IS3980S_MOSI_LOW(pcb_index) \
  155.         do{ \
  156.         switch(pcb_index) \
  157.         { \
  158.             case CPU_IS3980S: \
  159.                                 gpio_bits_write(CPU_IS3980S_MOSI_GPIO, CPU_IS3980S_MOSI_PIN, FALSE); \
  160.                             break; \
  161.                         case KEY_IS3980S: \
  162.                                 gpio_bits_write(KEY_IS3980S_MOSI_GPIO, KEY_IS3980S_MOSI_PIN, FALSE); \
  163.                                 break; \
  164.                         default:   \
  165.                                 break; \
  166.         }\
  167.         }while(0);

  168. #define IS3980S_READ_MISO_CPU()  gpio_input_data_bit_read(CPU_IS3980S_MISO_GPIO, CPU_IS3980S_MISO_PIN)
  169. #define IS3980S_READ_MISO_KEY()  gpio_input_data_bit_read(KEY_IS3980S_MISO_GPIO, KEY_IS3980S_MISO_PIN)

  170. //delay time
  171. #define IS3980S_DELAY_TIME  25
  172. #define IS3980S_SYNC_TIME   10

  173. /*SPI data*/
  174. typedef struct
  175. {
  176.     u8 ctrl_byte; //control byte
  177.     u8 addr_byte; //address byte
  178.     u8 data_byte; //data byte
  179. }is3980s_spi_data_t;
  180. extern is3980s_spi_data_t is3980s_data;

  181. /*chip register address*/
  182. typedef enum {
  183.     IS3980S_CHAN_STATUS_REG = 0x00,  //status register,8bit,only read,show input status of 8 channels
  184.         IS3980S_BDNC_MODE0_REG  = 0x01,  //filter mode set register, A1~A4 channels config
  185.         IS3980S_BDNC_MODE1_REG  = 0x02,  //A5~A8 channels config
  186.         IS3980S_BDNC_DLY0_REG   = 0x03,  //filter time set register, A1~A4 channels config
  187.         IS3980S_BDNC_DLY1_REG   = 0x04,  //A5~A8 channels config
  188. }is3980s_reg_addr_e;

  189. /*read and write cmd config*/
  190. typedef enum {
  191.         IS3980S_RW_WRITE = 0,
  192.         IS3980S_RW_READ  = 1,
  193. }is3980s_rw_command_e;

  194. /*define device id to write low 4 bits of control byte, CID[3:0]*/
  195. typedef enum {
  196.         IS3980S_CID_0 = 0,  //connect spi master when config which CID
  197.         IS3980S_CID_1,
  198.         IS3980S_CID_2,
  199.         IS3980S_CID_3,
  200.         IS3980S_CID_4,
  201. }is3980s_cid_e;

  202. /*define boradcast cmd to write bit7 of control byte*/
  203. typedef enum {
  204.         IS3980S_BRCT_DISABLE = 0, //only operate CID device of addressing
  205.         IS3980S_BRCT_ENABLE  = 1, //operate all CID devices of daisy chain
  206. }is3980s_op_brct_e;

  207. /*define common rw data of control byte*/
  208. typedef enum {
  209.         CTRL_DATA_BRCT_W = 0x80, //broadcast+write: 1000 0000
  210.         CTRL_DATA_W_CID_0 = 0x00, //unicast+write CID_0: 0000 0000
  211.         CTRL_DATA_W_CID_1 = 0x08, //unicast+write CID_1: 0000 1000
  212.         CTRL_DATA_R_CID_0 = 0x40, //unicast+read CID_0: 0100 0000
  213.         CTRL_DATA_R_CID_1 = 0x48, //unicast+read CID_1: 0100 1000
  214.         CTRL_DATA_R_CID_2 = 0x44, //unicast+read CID_2: 0100 0100
  215.         CTRL_DATA_R_CID_3 = 0x4C, //unicast+read CID_3: 0100 1100
  216.         CTRL_DATA_R_CID_4 = 0x42, //unicast+read CID_0: 0100 0010
  217. }is3980s_op_ctrl_data_e;

  218. extern void is3980s_all_init(void);
  219. extern void is3980s_init(uint8_t pcb_index, uint8_t nss_index);
  220. extern void is3980s_write(uint8_t pcb_index, uint8_t nss_index, uint8_t *write_buff, uint8_t len);
  221. extern void is3980s_read(uint8_t pcb_index, uint8_t nss_index, uint8_t *read_buff, uint8_t len);
  222. extern void is3980s_write_byte(uint8_t pcb_index, uint8_t nss_index, uint8_t write_byte);
  223. extern uint8_t is3980s_read_byte(uint8_t pcb_index, uint8_t nss_index);
  224. extern void is3980s_sync(uint8_t pcb_index, uint8_t nss_index);
  225. extern void is3980s_set_filter(uint8_t pcb_index, uint8_t nss_index, uint8_t filter_mode, uint8_t filter_time);

  226. #endif /* __IS3980S_H__ */
源文件如下所示:
  1. #include "is3980s.h"

  2. is3980s_spi_data_t is3980s_data;
  3. uint8_t test_data[2];

  4. /* init all IS3980S CHIP */
  5. void is3980s_all_init(void)
  6. {
  7.     uint8_t i = 0;
  8.         uint8_t j = 0;

  9.         for(i=0; i<IS3980S_MAX; i++)
  10.         {
  11.             for(j=0; j<IS3980S_NSS_MAX; j++)
  12.             {
  13.                 is3980s_init(i, j);
  14.             }
  15.         }
  16. }


  17. /* config IS3980S */
  18. void is3980s_init(uint8_t pcb_index, uint8_t nss_index)
  19. {
  20.         uint8_t spi_frame[IS3980S_SPI_DATA_LEN]; //control+address+data

  21.         /*pin config*/
  22.         IS3980S_NSS_HIGH(pcb_index, nss_index);
  23.         IS3980S_SCK_HIGH(pcb_index);
  24.         IS3980S_MOSI_LOW(pcb_index);

  25.         /*config when power on to make sure chip can work stable*/
  26.         //write data 0x55 to address 0x0A
  27.         spi_frame[0] = CTRL_DATA_BRCT_W;
  28.         spi_frame[1] = 0x0A;
  29.         spi_frame[2] = 0x55;
  30.         is3980s_write(pcb_index, nss_index, spi_frame, IS3980S_SPI_DATA_LEN);
  31.         //write data 0x44 to address 0x09
  32.         spi_frame[1] = 0x09;
  33.         spi_frame[2] = 0x44;
  34.         is3980s_write(pcb_index, nss_index, spi_frame, IS3980S_SPI_DATA_LEN);
  35.         //write data 0x00 to address 0x0A
  36.         spi_frame[1] = 0x0A;
  37.         spi_frame[2] = 0x00;
  38.         is3980s_write(pcb_index, nss_index, spi_frame, IS3980S_SPI_DATA_LEN);
  39. }

  40. /*inaccuracy delay*/
  41. static void is3980s_delay(uint32_t count)
  42. {
  43.         uint32_t i;
  44.        
  45.         for(i = 0; i < count; i++)
  46.         {
  47.                 __asm("nop");
  48.         }
  49. }

  50. /*get miso pin data*/
  51. static uint8_t is3980s_get_miso(uint8_t pcb_index)
  52. {
  53.     uint8_t value = 0;
  54.   
  55.     if(CPU_IS3980S == pcb_index)
  56.     {
  57.         value = IS3980S_READ_MISO_CPU();
  58.     }
  59.         else if(KEY_IS3980S == pcb_index)
  60.         {
  61.             value = IS3980S_READ_MISO_KEY();
  62.         }
  63.         return value;
  64. }


  65. /*write datas*/
  66. void is3980s_write(uint8_t pcb_index, uint8_t nss_index, uint8_t *write_buff, uint8_t len)
  67. {
  68.         uint8_t i;
  69.        
  70.         for(i=0; i < len; i++)
  71.         {
  72.                 is3980s_write_byte(pcb_index, nss_index, write_buff[i]);
  73.         }
  74. }

  75. /*read datas*/
  76. void is3980s_read(uint8_t pcb_index, uint8_t nss_index, uint8_t *read_buff, uint8_t len)
  77. {
  78.         uint8_t i;
  79.        
  80.         for(i=0; i < len; i++)
  81.         {
  82.                 read_buff[i] = is3980s_read_byte(pcb_index, nss_index);
  83.         }
  84. }

  85. /*write byte data*/
  86. void is3980s_write_byte(uint8_t pcb_index, uint8_t nss_index, uint8_t write_byte)
  87. {
  88.         uint8_t i;
  89.        
  90.         IS3980S_NSS_LOW(pcb_index, nss_index);
  91.         is3980s_delay(IS3980S_DELAY_TIME);
  92.         for(i = 0; i<8; i++)
  93.         {
  94.                 IS3980S_SCK_LOW(pcb_index);
  95.                 if(write_byte & 0x80)
  96.                 {
  97.                         IS3980S_MOSI_HIGH(pcb_index);
  98.                 }
  99.                 else
  100.                 {
  101.                         IS3980S_MOSI_LOW(pcb_index);
  102.                 }
  103.                 write_byte <<= 1;
  104.                 is3980s_delay(IS3980S_DELAY_TIME);
  105.                 IS3980S_SCK_HIGH(pcb_index);
  106.                 is3980s_delay(IS3980S_DELAY_TIME);
  107.         }
  108.         is3980s_delay(IS3980S_DELAY_TIME);
  109.         IS3980S_NSS_HIGH(pcb_index, nss_index);
  110.         is3980s_delay(IS3980S_DELAY_TIME);
  111. }

  112. /*read byte data*/
  113. uint8_t is3980s_read_byte(uint8_t pcb_index, uint8_t nss_index)
  114. {
  115.         uint8_t read_byte = 0;
  116.         uint8_t i;

  117.         IS3980S_NSS_LOW(pcb_index, nss_index);
  118.         is3980s_delay(3);
  119.         for(i = 0; i<8; i++)
  120.         {
  121.                 IS3980S_SCK_LOW(pcb_index);
  122.                 is3980s_delay(IS3980S_DELAY_TIME);
  123.                 IS3980S_SCK_HIGH(pcb_index);
  124.                 read_byte = read_byte << 1;
  125.                 //is3980s_delay(5);
  126.                 if(is3980s_get_miso(pcb_index))
  127.                 {
  128.                         read_byte |= 0x01;
  129.                 }
  130.                 else
  131.                 {
  132.                         read_byte &= ~0x01;
  133.                 }
  134.                 //IS3980S_SCK_HIGH(pcb_index);
  135.                 is3980s_delay(IS3980S_DELAY_TIME);
  136.         }
  137.         is3980s_delay(IS3980S_DELAY_TIME);
  138.         IS3980S_NSS_HIGH(pcb_index, nss_index);
  139.         is3980s_delay(3);
  140.         return read_byte;
  141. }

  142. /*send sync signal*/
  143. void is3980s_sync(uint8_t pcb_index, uint8_t nss_index)
  144. {
  145.         IS3980S_NSS_HIGH(pcb_index, nss_index);

  146.         IS3980S_SCK_LOW(pcb_index);
  147.         is3980s_delay(IS3980S_SYNC_TIME);
  148.         IS3980S_SCK_HIGH(pcb_index);
  149.         is3980s_delay(IS3980S_SYNC_TIME);
  150.         IS3980S_SCK_HIGH(pcb_index);
  151.         is3980s_delay(IS3980S_SYNC_TIME);
  152. }

  153. /*set filter time*/
  154. void is3980s_set_filter(uint8_t pcb_index, uint8_t nss_index, uint8_t filter_mode, uint8_t filter_time)
  155. {
  156.         uint8_t spi_frame[IS3980S_SPI_DATA_LEN];

  157.         is3980s_sync(pcb_index, nss_index);

  158.         /*config filter mode for A1~A4 channel*/
  159.         spi_frame[0] = CTRL_DATA_BRCT_W;
  160.         spi_frame[1] = IS3980S_BDNC_MODE0_REG;
  161.         spi_frame[2] = filter_mode;
  162.         is3980s_write(pcb_index, nss_index, spi_frame, IS3980S_SPI_DATA_LEN);

  163.         /*config filter mode for A5~A8 channel*/
  164.         spi_frame[1] = IS3980S_BDNC_MODE1_REG;
  165.         spi_frame[2] = filter_mode;
  166.         is3980s_write(pcb_index, nss_index, spi_frame, IS3980S_SPI_DATA_LEN);

  167.         /*config filter time for A5~A8 channel*/
  168.         spi_frame[1] = IS3980S_BDNC_DLY0_REG;
  169.         spi_frame[2] = filter_time;
  170.         is3980s_write(pcb_index, nss_index, spi_frame, IS3980S_SPI_DATA_LEN);

  171.         /*config filter time for A5~A8 channel*/
  172.         spi_frame[1] = IS3980S_BDNC_DLY1_REG;
  173.         spi_frame[2] = filter_time;
  174.         is3980s_write(pcb_index, nss_index, spi_frame, IS3980S_SPI_DATA_LEN);

  175.         //readback test
  176. //        is3980s_write_byte(pcb_index, nss_index, CTRL_DATA_R_CID_0);
  177. //        is3980s_write_byte(pcb_index, nss_index, IS3980S_BDNC_DLY0_REG);
  178. //        test_data[0] = is3980s_read_byte();
  179. //        is3980s_write_byte(pcb_index, nss_index, CTRL_DATA_R_CID_1);
  180. //        is3980s_write_byte(pcb_index, nss_index, IS3980S_BDNC_DLY1_REG);
  181. //        test_data[1] = is3980s_read_byte(pcb_index, nss_index);
  182. }
显而易见,基本上每个函数接口都带有两个形参:
uint8_t pcb_index

uint8_t nss_index
最原始的驱动代码其实是下面这个造型:
当我们在实际应用的时候,首先就要分时复用,通过NSS信号来激活其中一个芯片,类似下面的代码,拉高NSS信号即deactive芯片:
  1. static void cpu_spi_active_config(uint8_t chip_index)
  2. {
  3.     switch(chip_index)
  4.     {
  5.         case CPU_SPI_IS3980S_ENCODER:
  6.                 {
  7.                         IS3980S_NSS_HIGH(CPU_IS3980S, CPU_IS3980S_NSS2);
  8.                         break;
  9.                 }
  10.                 case CPU_SPI_IS3980S_DI:
  11.                 {
  12.                         IS3980S_NSS_HIGH(CPU_IS3980S, CPU_IS3980S_NSS1);
  13.                         break;
  14.                 }
  15.                 default:
  16.                 {
  17.                         IS3980S_NSS_HIGH(CPU_IS3980S, CPU_IS3980S_NSS1);
  18.                         IS3980S_NSS_HIGH(CPU_IS3980S, CPU_IS3980S_NSS2);
  19.                         break;
  20.                 }
  21.     }
  22. }

  23. static void key_spi_active_config(uint8_t chip_index)
  24. {
  25.     switch(chip_index)
  26.     {
  27.         case KEY_SPI_IS3980S_CN631:
  28.                 {
  29.                         IS3980S_NSS_HIGH(KEY_IS3980S, KEY_IS3980S_NSS2);
  30.                         break;
  31.                 }
  32.                 case KEY_SPI_IS3980S_CN748:
  33.                 {
  34.                         IS3980S_NSS_HIGH(KEY_IS3980S, KEY_IS3980S_NSS1);
  35.                         break;
  36.                 }
  37.                 default:
  38.                 {
  39.                         IS3980S_NSS_HIGH(KEY_IS3980S, KEY_IS3980S_NSS1);
  40.                         IS3980S_NSS_HIGH(KEY_IS3980S, KEY_IS3980S_NSS2);
  41.                         break;
  42.                 }
  43.     }
  44. }
然后在对应位置使用下面的接口即可进行数据读取:
  1. di_data0 = di_thread(CPU_IS3980S, CPU_IS3980S_NSS1);
  2. di_data1 = di_thread(CPU_IS3980S, CPU_IS3980S_NSS2);       
  3. di_data2 = di_thread(KEY_IS3980S, KEY_IS3980S_NSS1);       
  4. di_data3 = di_thread(KEY_IS3980S, KEY_IS3980S_NSS2);       
其中di_thread这个线程函数里面就是读写输入数据的代码,其形参也是uint8_t pcb_index和uint8_t nss_index:
  1. uint8_t di_thread(uint8_t pcb_index, uint8_t nss_index)
  2. {
  3.         uint8_t di_write_data = 0;
  4.         uint8_t di_read_data = 0;
  5.         //sync
  6.         is3980s_sync(pcb_index, nss_index);
  7.         di_write_data = di_set_cid_data(0);
  8.         is3980s_write(pcb_index, nss_index, &di_write_data, 1);
  9.         di_write_data = IS3980S_CHAN_STATUS_REG;
  10.         is3980s_write(pcb_index, nss_index, &di_write_data, 1);
  11.         is3980s_read(pcb_index, nss_index, &di_read_data, 1);
  12.         return di_read_data;
  13. }
对于更多类似的硬件设计,通过这种方法实现的驱动代码里面的各个函数接口,基本上每个都会携带pcb_index和nss_index参数,然后函数里面的代码都会涉及,看着是有点复杂,但是扩展性和维护性相对来说还是不错的。当然,你还可以视具体情况增加更多的index来识别。

话说回来,这种设计肯定不是最好最优的,毕竟仁者见仁,智者见智,比如也可以通过定义结构体+表驱动法来实现;这里咱就权当是抛砖引玉,有更好的想法和设计的大神请不吝赐教~~

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×

打赏榜单

21小跑堂 打赏了 30.00 元 2026-07-13
理由:恭喜通过原创审核!期待您更多的原创作品~

评论

该文章从软件架构设计的层面切入。作者通过实际案例展示了如何利用C语言的宏定义和参数传递机制,解决嵌入式开发中常见的硬件资源冲突与管理...  发表于 2026-7-13 16:11
gaoyang9992006 发表于 2026-6-10 09:29 | 显示全部楼层
代码的TAB设置一下,用空格代替,不然贴出来就这样了。
 楼主| dffzh 发表于 2026-6-10 10:28 | 显示全部楼层
gaoyang9992006 发表于 2026-6-10 09:29
代码的TAB设置一下,用空格代替,不然贴出来就这样了。

编码一般都是用空格缩进的,估计是代码编辑器的原因
您需要登录后才可以回帖 登录 | 注册

本版积分规则

544

主题

3898

帖子

26

粉丝
快速回复 在线客服 返回列表 返回顶部
0