{"id":3142,"date":"2025-01-10T05:05:50","date_gmt":"2025-01-10T05:05:50","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=3142"},"modified":"2025-01-10T05:05:52","modified_gmt":"2025-01-10T05:05:52","slug":"creating-a-library-for-pca9685-pwm-module-part-2-creating-the-library","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=3142","title":{"rendered":"Creating a Library for PCA9685 PWM module Part 2: Creating the library"},"content":{"rendered":"<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"1024\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/39110e75-9027-44da-9e8c-2647503bff70-1.webp\" alt=\"\" class=\"wp-image-3143\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/39110e75-9027-44da-9e8c-2647503bff70-1.webp 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/39110e75-9027-44da-9e8c-2647503bff70-1-300x300.webp 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/39110e75-9027-44da-9e8c-2647503bff70-1-150x150.webp 150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/39110e75-9027-44da-9e8c-2647503bff70-1-768x768.webp 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/39110e75-9027-44da-9e8c-2647503bff70-1-750x750.webp 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/39110e75-9027-44da-9e8c-2647503bff70-1-400x400.webp 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/39110e75-9027-44da-9e8c-2647503bff70-1-250x250.webp 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n<p>In the second part of PCA9685 PWM module guide, we shall create the library that allow us to set the frequency and control the duty cycle of each individual channel.<\/p>\n\n\n\n<p>In this guide, we shall cover the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Creating the header and source file.<\/li>\n\n\n\n<li>Developing the header file.<\/li>\n\n\n\n<li>Developing the source file.<\/li>\n\n\n\n<li>Testing the library.<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">6. Creating the Header and Source Files:<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p>After the project has been generated by STM32CubeMX within STM32CubeIDE, we shall add new source file and header file.<\/p>\n\n\n\n<p>Right click on Src folder and add new source file as following:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"486\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/2024-11-07_07-03-43-1024x486.jpg\" alt=\"\" class=\"wp-image-2972\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/2024-11-07_07-03-43-1024x486.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/2024-11-07_07-03-43-300x142.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/2024-11-07_07-03-43-768x364.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/2024-11-07_07-03-43-1536x729.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/2024-11-07_07-03-43-2048x972.jpg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/2024-11-07_07-03-43-1150x546.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/2024-11-07_07-03-43-750x356.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/2024-11-07_07-03-43-400x190.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/2024-11-07_07-03-43-250x119.jpg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Give a name for the source file, we shall name it as PCA9685.c as following:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"734\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-05-42-1024x734.jpg\" alt=\"\" class=\"wp-image-3144\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-05-42-1024x734.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-05-42-300x215.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-05-42-768x550.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-05-42-1150x824.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-05-42-750x538.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-05-42-400x287.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-05-42-250x179.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-05-42.jpg 1172w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>In similar manner, right click on Inc folder and add new header file with name of PCA9685.h.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">7. Developing the Header File:<\/h2>\n\n\n\n<p>Start off by including the stdint header file as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;stdint.h&quot;<\/pre><\/div>\n\n\n\n<p>Then, declare the following enumeration which holds the channels of the module as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">typedef enum\n{\n\tCH0=0,\n\tCH1,\n\tCH2,\n\tCH3,\n\tCH4,\n\tCH5,\n\tCH6,\n\tCH7,\n\tCH8,\n\tCH9,\n\tCH10,\n\tCH11,\n\tCH12,\n\tCH13,\n\tCH14,\n\tCH15\n\n}PCA9685_ChannelTypedef;<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, we shall define all the registers of the module as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\/\/ Mode Registers\n#define PCA9685_MODE1          0x00  \/\/ Mode register 1\n#define PCA9685_MODE2          0x01  \/\/ Mode register 2\n\n\/\/ Subaddress Registers\n#define PCA9685_SUBADR1        0x02  \/\/ I2C-bus subaddress 1\n#define PCA9685_SUBADR2        0x03  \/\/ I2C-bus subaddress 2\n#define PCA9685_SUBADR3        0x04  \/\/ I2C-bus subaddress 3\n\n\/\/ All Call Address Register\n#define PCA9685_ALLCALLADR     0x05  \/\/ LED All Call I2C address\n\n\/\/ LED Output and PWM Control Registers\n#define PCA9685_LED0_ON_L      0x06  \/\/ LED0 output and brightness control - ON low byte\n#define PCA9685_LED0_ON_H      0x07  \/\/ LED0 output and brightness control - ON high byte\n#define PCA9685_LED0_OFF_L     0x08  \/\/ LED0 output and brightness control - OFF low byte\n#define PCA9685_LED0_OFF_H     0x09  \/\/ LED0 output and brightness control - OFF high byte\n\n#define PCA9685_LED1_ON_L      0x0A  \/\/ LED1 output and brightness control - ON low byte\n#define PCA9685_LED1_ON_H      0x0B  \/\/ LED1 output and brightness control - ON high byte\n#define PCA9685_LED1_OFF_L     0x0C  \/\/ LED1 output and brightness control - OFF low byte\n#define PCA9685_LED1_OFF_H     0x0D  \/\/ LED1 output and brightness control - OFF high byte\n\n\/\/ Repeat for all 16 channels\n#define PCA9685_LED2_ON_L      0x0E\n#define PCA9685_LED2_ON_H      0x0F\n#define PCA9685_LED2_OFF_L     0x10\n#define PCA9685_LED2_OFF_H     0x11\n\/\/ ...\n#define PCA9685_LED15_ON_L     0x42\n#define PCA9685_LED15_ON_H     0x43\n#define PCA9685_LED15_OFF_L    0x44\n#define PCA9685_LED15_OFF_H    0x45\n\n\/\/ All LEDs Control\n#define PCA9685_ALL_LED_ON_L   0xFA  \/\/ Load all LEDn_ON registers, low byte\n#define PCA9685_ALL_LED_ON_H   0xFB  \/\/ Load all LEDn_ON registers, high byte\n#define PCA9685_ALL_LED_OFF_L  0xFC  \/\/ Load all LEDn_OFF registers, low byte\n#define PCA9685_ALL_LED_OFF_H  0xFD  \/\/ Load all LEDn_OFF registers, high byte\n\n\/\/ Prescaler Register\n#define PCA9685_PRESCALE       0xFE  \/\/ Prescaler for PWM output frequency\n\n\/\/ Test Mode Register (Not recommended for normal use)\n#define PCA9685_TESTMODE       0xFF  \/\/ Test mode register\n\n#define FREQUENCY_OSCILLATOR 25000000 \/**&lt; Int. osc. frequency in datasheet *\/\n\n#define PCA9685_PRESCALE_MIN 3   \/**&lt; minimum prescale value *\/\n#define PCA9685_PRESCALE_MAX 255 \/**&lt; maximum prescale value *\/<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, we shall declare a function that allows the use to change the default address as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void PCA9685SetAddr(uint8_t add);<\/pre><\/div>\n\n\n\n<p>The function takes the new address as argument and returns no thing.<\/p>\n\n\n\n<p>Next, a function that will initialize the module with the desired frequency:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void PCA9685_Init(uint16_t freq);<\/pre><\/div>\n\n\n\n<p>The function will intialize the module and take the desired frequency as argument and return nothing.<\/p>\n\n\n\n<p>Declare a function that will set the duty cycle of the desired channel as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void PCA9685_SetPWMDutyCycle(PCA9685_ChannelTypedef ch, uint8_t dutyCycle);<\/pre><\/div>\n\n\n\n<p>The function takes the following parameters:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Channel number (from 0 to 15).<\/li>\n\n\n\n<li>Duty cycle of the channel.<\/li>\n<\/ul>\n\n\n\n<p>Hence, the entire header file as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#ifndef INC_PCA9685_H_\n#define INC_PCA9685_H_\n\n#include &quot;stdint.h&quot;\n\n\ntypedef enum\n{\n\tCH0=0,\n\tCH1,\n\tCH2,\n\tCH3,\n\tCH4,\n\tCH5,\n\tCH6,\n\tCH7,\n\tCH8,\n\tCH9,\n\tCH10,\n\tCH11,\n\tCH12,\n\tCH13,\n\tCH14,\n\tCH15\n\n}PCA9685_ChannelTypedef;\n\n\n\/\/ Mode Registers\n#define PCA9685_MODE1          0x00  \/\/ Mode register 1\n#define PCA9685_MODE2          0x01  \/\/ Mode register 2\n\n\/\/ Subaddress Registers\n#define PCA9685_SUBADR1        0x02  \/\/ I2C-bus subaddress 1\n#define PCA9685_SUBADR2        0x03  \/\/ I2C-bus subaddress 2\n#define PCA9685_SUBADR3        0x04  \/\/ I2C-bus subaddress 3\n\n\/\/ All Call Address Register\n#define PCA9685_ALLCALLADR     0x05  \/\/ LED All Call I2C address\n\n\/\/ LED Output and PWM Control Registers\n#define PCA9685_LED0_ON_L      0x06  \/\/ LED0 output and brightness control - ON low byte\n#define PCA9685_LED0_ON_H      0x07  \/\/ LED0 output and brightness control - ON high byte\n#define PCA9685_LED0_OFF_L     0x08  \/\/ LED0 output and brightness control - OFF low byte\n#define PCA9685_LED0_OFF_H     0x09  \/\/ LED0 output and brightness control - OFF high byte\n\n#define PCA9685_LED1_ON_L      0x0A  \/\/ LED1 output and brightness control - ON low byte\n#define PCA9685_LED1_ON_H      0x0B  \/\/ LED1 output and brightness control - ON high byte\n#define PCA9685_LED1_OFF_L     0x0C  \/\/ LED1 output and brightness control - OFF low byte\n#define PCA9685_LED1_OFF_H     0x0D  \/\/ LED1 output and brightness control - OFF high byte\n\n\/\/ Repeat for all 16 channels\n#define PCA9685_LED2_ON_L      0x0E\n#define PCA9685_LED2_ON_H      0x0F\n#define PCA9685_LED2_OFF_L     0x10\n#define PCA9685_LED2_OFF_H     0x11\n\/\/ ...\n#define PCA9685_LED15_ON_L     0x42\n#define PCA9685_LED15_ON_H     0x43\n#define PCA9685_LED15_OFF_L    0x44\n#define PCA9685_LED15_OFF_H    0x45\n\n\/\/ All LEDs Control\n#define PCA9685_ALL_LED_ON_L   0xFA  \/\/ Load all LEDn_ON registers, low byte\n#define PCA9685_ALL_LED_ON_H   0xFB  \/\/ Load all LEDn_ON registers, high byte\n#define PCA9685_ALL_LED_OFF_L  0xFC  \/\/ Load all LEDn_OFF registers, low byte\n#define PCA9685_ALL_LED_OFF_H  0xFD  \/\/ Load all LEDn_OFF registers, high byte\n\n\/\/ Prescaler Register\n#define PCA9685_PRESCALE       0xFE  \/\/ Prescaler for PWM output frequency\n\n\/\/ Test Mode Register (Not recommended for normal use)\n#define PCA9685_TESTMODE       0xFF  \/\/ Test mode register\n\n#define FREQUENCY_OSCILLATOR 25000000 \/**&lt; Int. osc. frequency in datasheet *\/\n\n#define PCA9685_PRESCALE_MIN 3   \/**&lt; minimum prescale value *\/\n#define PCA9685_PRESCALE_MAX 255 \/**&lt; maximum prescale value *\/\n\n\nvoid PCA9685SetAddr(uint8_t add);\n\n\nvoid PCA9685_Init(uint16_t freq);\n\nvoid PCA9685_SetPWMDutyCycle(PCA9685_ChannelTypedef ch, uint8_t dutyCycle);\n\n\n\n#endif \/* INC_PCA9685_H_ *\/<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">8. Developing the Source File:<\/h2>\n\n\n\n<p>Open PCA9685.c source file.<\/p>\n\n\n\n<p>We start off by including the PCA9685 header file as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;PCA9685.h&quot;<\/pre><\/div>\n\n\n\n<p>Include both main.h and i2c.h as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;main.h&quot;\n#include &quot;i2c.h&quot;<\/pre><\/div>\n\n\n\n<p>Next, declare the address of the module as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">static uint8_t PCA9685_ADDR = 0x40&lt;&lt;1;<\/pre><\/div>\n\n\n\n<p>The reason it is static, it won&#8217;t be used outside the current source file.<\/p>\n\n\n\n<p>Next, the function that will change the address as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void PCA9685SetAddr(uint8_t add)\n{\n\tPCA9685_ADDR=add&lt;&lt;1;\n}<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, the function that will initialize the module with the desired frequency:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void PCA9685_Init(uint16_t freq)\n{\n\n\tuint8_t data[2];\n\n\tdata[0] = PCA9685_MODE1;  \/\/ MODE1 register\n\tdata[1] = 0x30;  \/\/ Auto-increment and normal mode sleep on oscillator off\n\tHAL_I2C_Master_Transmit(&amp;hi2c1, (PCA9685_ADDR), data, 2, 100);\n\n\tfloat prescaleval = ((FREQUENCY_OSCILLATOR \/ (freq * 4096.0)));\n\t  if (prescaleval &lt; PCA9685_PRESCALE_MIN)\n\t    prescaleval = PCA9685_PRESCALE_MIN;\n\t  if (prescaleval &gt; PCA9685_PRESCALE_MAX)\n\t    prescaleval = PCA9685_PRESCALE_MAX;\n\n\t  uint8_t prescale = (uint8_t)prescaleval-1;\n\n\n\tdata[0] = PCA9685_PRESCALE;  \/\/ PRE_SCALE register\n\tdata[1] = prescale;\n\tHAL_I2C_Master_Transmit(&amp;hi2c1, (PCA9685_ADDR), data, 2, 100);\n\n\tdata[0] = PCA9685_MODE1;  \/\/ MODE1 register\n\tdata[1] = 0xA0;\n\tHAL_I2C_Master_Transmit(&amp;hi2c1, (PCA9685_ADDR), data, 2, 100);\n\n\n\n}<\/pre><\/div>\n\n\n\n<p>First, declare a buffer of two bytes to hold the data to be transmitted.<\/p>\n\n\n\n<p>Next, set the module into sleep mode and enable auto address increment as following:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"929\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-23-53-1024x929.jpg\" alt=\"\" class=\"wp-image-3145\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-23-53-1024x929.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-23-53-300x272.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-23-53-768x697.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-23-53-1536x1393.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-23-53-1150x1043.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-23-53-750x680.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-23-53-400x363.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-23-53-250x227.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-23-53.jpg 1936w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Then write the data to MODE1 register as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">uint8_t data[2];\ndata[0] = PCA9685_MODE1;  \/\/ MODE1 register\ndata[1] = 0x30;  \/\/ Auto-increment and normal mode sleep on oscillator off\nHAL_I2C_Master_Transmit(&amp;hi2c1, (PCA9685_ADDR), data, 2, 100);<\/pre><\/div>\n\n\n\n<p>Next, we shall calculate the prescaler to to generate the desired frequency as following:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"194\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-26-45-1024x194.jpg\" alt=\"\" class=\"wp-image-3147\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-26-45-1024x194.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-26-45-300x57.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-26-45-768x146.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-26-45-1150x218.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-26-45-750x142.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-26-45-400x76.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-26-45-250x47.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-26-45.jpg 1412w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Write the new prescaler values to the prescaler register as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\tfloat prescaleval = ((FREQUENCY_OSCILLATOR \/ (freq * 4096.0)));\n\t  if (prescaleval &lt; PCA9685_PRESCALE_MIN)\n\t    prescaleval = PCA9685_PRESCALE_MIN;\n\t  if (prescaleval &gt; PCA9685_PRESCALE_MAX)\n\t    prescaleval = PCA9685_PRESCALE_MAX;\n\n\t  uint8_t prescale = (uint8_t)prescaleval-1;\n\n\n\tdata[0] = PCA9685_PRESCALE;  \/\/ PRE_SCALE register\n\tdata[1] = prescale;\n\tHAL_I2C_Master_Transmit(&amp;hi2c1, (PCA9685_ADDR), data, 2, 100);<\/pre><\/div>\n\n\n\n<p>Next, restart the module the enable the auto address increment as following:<\/p>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"896\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-28-30-1024x896.jpg\" alt=\"\" class=\"wp-image-3148\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-28-30-1024x896.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-28-30-300x262.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-28-30-768x672.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-28-30-1536x1344.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-28-30-2048x1792.jpg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-28-30-1150x1006.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-28-30-750x656.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-28-30-400x350.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/2025-01-10_07-28-30-250x219.jpg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">data[0] = PCA9685_MODE1;  \/\/ MODE1 register\ndata[1] = 0xA0;\nHAL_I2C_Master_Transmit(&amp;hi2c1, (PCA9685_ADDR), data, 2, 100);<\/pre><\/div>\n\n\n\n<p>Next the function to set the duty cycle of the c hannel:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void PCA9685_SetPWMDutyCycle(PCA9685_ChannelTypedef ch, uint8_t dutyCycle)\n{\n\n\tif(dutyCycle&gt;100)dutyCycle=100;\n    if (ch&gt;CH15) return;\n\n    uint16_t ON_count = 0;  \/\/ Start at 0\n    uint16_t OFF_count = (uint16_t)((dutyCycle * 4096) \/ 100);\n\n    \/\/ Calculate register addresses\n    uint8_t reg_base = PCA9685_LED0_ON_L + 4 * ch;\n\n    \/\/ Prepare data for the ON and OFF registers\n    uint8_t data[4];\n    data[0] = ON_count &amp; 0xFF;         \/\/ LEDn_ON_L\n    data[1] = (ON_count &gt;&gt; 8) &amp; 0x0F; \/\/ LEDn_ON_H\n    data[2] = OFF_count &amp; 0xFF;        \/\/ LEDn_OFF_L\n    data[3] = (OFF_count &gt;&gt; 8) &amp; 0x0F; \/\/ LEDn_OFF_H\n\n    \/\/ Write data to the PCA9685\n    HAL_I2C_Mem_Write(&amp;hi2c1, PCA9685_ADDR, reg_base, I2C_MEMADD_SIZE_8BIT, data, 4, HAL_MAX_DELAY);\n}<\/pre><\/div>\n\n\n\n<p>First, check if the duty cycle is beyond the 100, if it is, set it to 100 as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">if(dutyCycle&gt;100)dutyCycle=100;<\/pre><\/div>\n\n\n\n<p>If the channel number is beyond the 15, exit the channel:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">if (ch&gt;CH15) return;<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>We start by setting the On count to 0 and off count to be the desired duty cycle as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">uint16_t ON_count = 0;  \/\/ Start at 0\nuint16_t OFF_count = (uint16_t)((dutyCycle * 4096) \/ 100);<\/pre><\/div>\n\n\n\n<p>Next, we shall calculate the address as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">    \/\/ Calculate register addresses\n    uint8_t reg_base = PCA9685_LED0_ON_L + 4 * ch;<\/pre><\/div>\n\n\n\n<p>Start by the LED0_ON_L address and multiply the channel by 4 then add it to the address and you will get the desired address.<\/p>\n\n\n\n<p>Convert the duty cycle 4 bytes as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">    uint8_t data[4];\n    data[0] = ON_count &amp; 0xFF;         \/\/ LEDn_ON_L\n    data[1] = (ON_count &gt;&gt; 8) &amp; 0x0F; \/\/ LEDn_ON_H\n    data[2] = OFF_count &amp; 0xFF;        \/\/ LEDn_OFF_L\n    data[3] = (OFF_count &gt;&gt; 8) &amp; 0x0F; \/\/ LEDn_OFF_H\n\n    \/\/ Write data to the PCA9685\n    HAL_I2C_Mem_Write(&amp;hi2c1, PCA9685_ADDR, reg_base, I2C_MEMADD_SIZE_8BIT, data, 4, HAL_MAX_DELAY);<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Hence, the entire source file as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;PCA9685.h&quot;\n#include &quot;main.h&quot;\n#include &quot;i2c.h&quot;\n\nstatic uint8_t PCA9685_ADDR = 0x40&lt;&lt;1;\n\n\nvoid PCA9685SetAddr(uint8_t add)\n{\n\tPCA9685_ADDR=add&lt;&lt;1;\n}\n\n\n\nvoid PCA9685_Init(uint16_t freq)\n{\n\n\tuint8_t data[2];\n\n\tdata[0] = PCA9685_MODE1;  \/\/ MODE1 register\n\tdata[1] = 0x30;  \/\/ Auto-increment and normal mode sleep on oscillator off\n\tHAL_I2C_Master_Transmit(&amp;hi2c1, (PCA9685_ADDR), data, 2, 100);\n\n\tfloat prescaleval = ((FREQUENCY_OSCILLATOR \/ (freq * 4096.0)));\n\t  if (prescaleval &lt; PCA9685_PRESCALE_MIN)\n\t    prescaleval = PCA9685_PRESCALE_MIN;\n\t  if (prescaleval &gt; PCA9685_PRESCALE_MAX)\n\t    prescaleval = PCA9685_PRESCALE_MAX;\n\n\t  uint8_t prescale = (uint8_t)prescaleval-1;\n\n\n\tdata[0] = PCA9685_PRESCALE;  \/\/ PRE_SCALE register\n\tdata[1] = prescale;\n\tHAL_I2C_Master_Transmit(&amp;hi2c1, (PCA9685_ADDR), data, 2, 100);\n\n\tdata[0] = PCA9685_MODE1;  \/\/ MODE1 register\n\tdata[1] = 0xA0;\n\tHAL_I2C_Master_Transmit(&amp;hi2c1, (PCA9685_ADDR), data, 2, 100);\n\n}\n\n\n\n\nvoid PCA9685_SetPWMDutyCycle(PCA9685_ChannelTypedef ch, uint8_t dutyCycle)\n{\n\n\tif(dutyCycle&gt;100)dutyCycle=100;\n\t\n\tif (ch&gt;CH15) return;\n\t\n    uint16_t ON_count = 0;  \/\/ Start at 0\n    uint16_t OFF_count = (uint16_t)((dutyCycle * 4096) \/ 100);\n\n    \/\/ Calculate register addresses\n    uint8_t reg_base = PCA9685_LED0_ON_L + 4 * ch;\n\n    \/\/ Prepare data for the ON and OFF registers\n    uint8_t data[4];\n    data[0] = ON_count &amp; 0xFF;         \/\/ LEDn_ON_L\n    data[1] = (ON_count &gt;&gt; 8) &amp; 0x0F; \/\/ LEDn_ON_H\n    data[2] = OFF_count &amp; 0xFF;        \/\/ LEDn_OFF_L\n    data[3] = (OFF_count &gt;&gt; 8) &amp; 0x0F; \/\/ LEDn_OFF_H\n\n    \/\/ Write data to the PCA9685\n    HAL_I2C_Mem_Write(&amp;hi2c1, PCA9685_ADDR, reg_base, I2C_MEMADD_SIZE_8BIT, data, 4, HAL_MAX_DELAY);\n}\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">9. Testing the Library:<\/h2>\n\n\n\n<p>Open main.c file.<\/p>\n\n\n\n<p>In user begin includes, include the header file as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;PCA9685.h&quot;<\/pre><\/div>\n\n\n\n<p>In user code begin 2, we shall initialize the module to 1KHz and set the first 4 channels as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">  \tPCA9685_Init(1000);\n  \tPCA9685_SetPWMDutyCycle(CH0, 25);\n  \tPCA9685_SetPWMDutyCycle(CH1, 50);\n  \tPCA9685_SetPWMDutyCycle(CH2, 75);\n  \tPCA9685_SetPWMDutyCycle(CH3, 40);<\/pre><\/div>\n\n\n\n<p>Save the project, build it and run it on your board as following:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"28\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/image-1024x28.png\" alt=\"\" class=\"wp-image-2982\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/image-1024x28.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/image-300x8.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/image-768x21.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/image-1536x43.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/image-1150x32.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/image-750x21.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/image-400x11.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/image-250x7.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/11\/image.png 1734w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>The screen shot below shows the results.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"480\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/DS1Z_QuickPrint1.png\" alt=\"\" class=\"wp-image-3149\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/DS1Z_QuickPrint1.png 800w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/DS1Z_QuickPrint1-300x180.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/DS1Z_QuickPrint1-768x461.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/DS1Z_QuickPrint1-750x450.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/DS1Z_QuickPrint1-400x240.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/01\/DS1Z_QuickPrint1-250x150.png 250w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/figure>\n\n\n\n<p>We are getting near the desired frequency and the duty cycles are identical to what we wrote in the code.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Happy coding \ud83d\ude09 <\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the second part of PCA9685 PWM module guide, we shall create the library that allow us to set the frequency and control the duty cycle of each individual channel. In this guide, we shall cover the following: 6. Creating the Header and Source Files: After the project has been generated by STM32CubeMX within STM32CubeIDE, [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,11,12],"tags":[],"class_list":["post-3142","post","type-post","status-publish","format-standard","hentry","category-embedded-systems","category-peripheral-drivers","category-stm32"],"_links":{"self":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/3142"}],"collection":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3142"}],"version-history":[{"count":2,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/3142\/revisions"}],"predecessor-version":[{"id":3150,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/3142\/revisions\/3150"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3142"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3142"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3142"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}