Writing device drivers for microcontrollers, where can IO IO Port contacts be identified?

I always face this dilemma when writing low-level code for the MCU. I never know where to declare pin definitions to make the code as reusable as possible.

In this case, Im writing a driver to connect the 8051 to the 12-bit MCP4922 DAC. Im unsure how / where I have to declare pin definitions for CS (chip selection) and LDAC (data latch) for the DAC. Currently in the header file for the driver is specified.

Iv did a lot of research trying to find a better approach, but havent really found something.

Basically I want to know what are the best practices ... if there are any books worth reading or online information, examples, etc., any recommendations would be welcome.

Just a driver fragment for you to understand the idea

/**
    @brief  This function is used to write a 16bit data word  to DAC B -12 data bit plus 4 configuration bits
    @param  dac_data A 12bit word 
    @param  ip_buf_unbuf_select Input Buffered/unbuffered  select bit. Buffered = 1; Unbuffered = 0
    @param  gain_select Output Gain Selection bit. 1 = 1x (VOUT = VREF * D/4096).  0 =2x (VOUT = 2 * VREF * D/4096)
*/
void MCP4922_DAC_B_TX_word(unsigned short int dac_data, bit ip_buf_unbuf_select, bit gain_select)
{                                             

    unsigned char low_byte=0, high_byte=0;
    CS = 0;                                               /**Select the chip*/

    high_byte |= ((0x01 << 7) | (0x01 << 4));            /**Set bit to select DAC A and Set SHDN bit high for DAC A active operation*/
    if(ip_buf_unbuf_select) high_byte |= (0x01 << 6);
    if(gain_select)         high_byte |= (0x01 << 5);

    high_byte |= ((dac_data >> 8) & 0x0F);
    low_byte |= dac_data;
    SPI_master_byte(high_byte);
    SPI_master_byte(low_byte);

    CS = 1;                                               
    LDAC = 0;                                             /**Latch the Data*/
    LDAC = 1;                                         
}
+3
source share
4 answers

This is what I did in a similar case, this example is for writing the I²C driver:

// Structure holding information about an I²C bus
struct IIC_BUS
{
    int pin_index_sclk;
    int pin_index_sdat;
};

// Initialize I²C bus structure with pin indices
void iic_init_bus( struct IIC_BUS* iic, int idx_sclk, int idx_sdat );

// Write data to an I²C bus, toggling the bits
void iic_write( struct IIC_BUS* iic, uint8_t iicAddress, uint8_t* data, uint8_t length );

All indexes are declared in the application-specific header file to provide a quick look, for example:

// ...
#define MY_IIC_BUS_SCLK_PIN 12
#define MY_IIC_BUS_SCLK_PIN 13
#define OTHER_PIN 14
// ...

In this example, the I²C bus implementation is fully portable. It depends only on the API, which can write on chips by index.

Edit:

This driver is used as follows:

// main.c
#include "iic.h"
#include "pin-declarations.h"

main()
{
    struct IIC_BUS mybus;
    iic_init_bus( &mybus, MY_IIC_BUS_SCLK_PIN, MY_IIC_BUS_SDAT_PIN );

    // ...

    iic_write( &mybus, 0x42, some_data_buffer, buffer_length );
}
+3
source

, , . , , , DMA USB. . , .

. - . . , .

+2

CS, , . , .

, CS, , . , , -; - .

+2

, ARM, PowerPC... 8051. #define, , . :

blah.h:

#define CSN_LOW()   CS = 0
#define CSN_HI()    CS = 1
#define LATCH_STROBE() \
 do { LDAC = 0; LDAC = 1; } while (0)

blah.c:
#include <blah.h>
void blah_update( U8 high, U8 low ) 
{
   CSN_LOW();
   SPI_master_byte(high);
   SPI_master_byte(low);
   CSN_HI();
   LATCH_STROBE();
} 

If you need to change the definition of the output or switch to another processor, this should be obvious when you need to update. And it also helps when you need to set the time on the bus (i.e., insert a delay here and there), since you do not need to change all the places. Hope this helps.

+2
source

Source: https://habr.com/ru/post/1747362/


All Articles