POC multiple PCA9685 (use AI btw)

This commit is contained in:
acki
2025-12-13 18:33:40 +01:00
parent 7eade1305b
commit 1251be5115
2 changed files with 80 additions and 35 deletions

View File

@@ -5,7 +5,6 @@
#include <stdbool.h>
#define NOMBRE_SERVOS 16
#define NOMBRE_POSITIONS_SERVOS 8
#define NOMBRE_POSITIONS_ASC 8
#define NOMBRE_RELAIS 3
@@ -23,7 +22,6 @@ typedef struct Actionneurs {
bool enJeu;
uint16_t armementTirette;
uint16_t angleServo[NOMBRE_SERVOS];
// uint16_t valeursPositionsServos[NOMBRE_SERVOS][NOMBRE_POSITIONS_SERVOS];
uint16_t positionAscenseur;
uint16_t valeursPositionsAscenseur[NOMBRE_POSITIONS_ASC];
GPIO_TypeDef * relayPorts[NOMBRE_RELAIS];

View File

@@ -3,10 +3,20 @@
#include "actio.h"
#include <math.h>
/* ######################## PARTIE PCA9685 SERVO ########################### */
#define PCA9685_ADDRESS 0x80
#define PCA9685_COUNT 2 // number of boards
#define PCA9685_BASE_ADDR 0x40 // A0=A1=A2=0
#define PCA9685_SERVOS_PER_BOARD 16
#define PCA9685_TOTAL_SERVOS (PCA9685_COUNT * PCA9685_SERVOS_PER_BOARD)
#define PCA9685_PWM_FREQ 50 // Hz
#define SERVO_MIN_PULSE 102 // 0.5 ms
#define SERVO_MAX_PULSE 512 // 2.5 ms
// Datasheet link --> https://cdn-shop.adafruit.com/datasheets/PCA9685.pdf
#define PCA9685_MODE1 0x0 // as in the datasheet page no 10/52
#define PCA9685_PRE_SCALE 0xFE // as in the datasheet page no 13/52
@@ -16,28 +26,38 @@
#define PCA9685_MODE1_RESTART_BIT 7 // as in the datasheet page no 14/52
void PCA9685_SetBit(uint8_t Register, uint8_t Bit, uint8_t Value);
void PCA9685_SetPWMFrequency(uint16_t frequency);
void PCA9685_Init(uint16_t frequency);
void PCA9685_SetPWM(uint8_t Channel, uint16_t OnTime, uint16_t OffTime);
void PCA9685_SetBit(uint8_t Address, uint8_t Register, uint8_t Bit, uint8_t Value);
void PCA9685_SetPWMFrequency(uint8_t Address, uint16_t frequency);
void PCA9685_Init(uint8_t Address, uint16_t frequency);
void PCA9685_InitAllBoards(uint16_t frequency);
void PCA9685_SetPWM(uint8_t Address, uint8_t Channel, uint16_t OnTime, uint16_t OffTime);
void PCA9685_SetServoAngle(uint8_t Channel, float Angle);
void PCA9685_ContinuousServoRun(uint8_t Channel);
void PCA9685_ContinuousServoStop(uint8_t Channel);
void PCA9685_ContinuousServoRun(uint8_t Channel); // 360 deg servo
void PCA9685_ContinuousServoStop(uint8_t Channel); // 360 deg servo
extern I2C_HandleTypeDef hi2c1;
void PCA9685_SetBit(uint8_t Register, uint8_t Bit, uint8_t Value)
static inline void servo_to_pca(uint16_t servo,
uint8_t *addr,
uint8_t *channel)
{
uint8_t board = servo / PCA9685_SERVOS_PER_BOARD;
*channel = servo % PCA9685_SERVOS_PER_BOARD;
*addr = PCA9685_BASE_ADDR + board;
}
void PCA9685_SetBit(uint8_t Address, uint8_t Register, uint8_t Bit, uint8_t Value)
{
uint8_t readValue;
// Read all 8 bits and set only one bit to 0/1 and write all 8 bits back
HAL_I2C_Mem_Read(&hi2c1, PCA9685_ADDRESS, Register, 1, &readValue, 1, 10);
HAL_I2C_Mem_Read(&hi2c1, Address << 1, Register, 1, &readValue, 1, 10);
if (Value == 0) readValue &= ~(1 << Bit);
else readValue |= (1 << Bit);
HAL_I2C_Mem_Write(&hi2c1, PCA9685_ADDRESS, Register, 1, &readValue, 1, 10);
HAL_I2C_Mem_Write(&hi2c1, Address << 1, Register, 1, &readValue, 1, 10);
HAL_Delay(1);
}
void PCA9685_SetPWMFrequency(uint16_t frequency)
void PCA9685_SetPWMFrequency(uint8_t Address, uint16_t frequency)
{
uint8_t prescale;
if(frequency >= 1526) prescale = 0x03;
@@ -45,59 +65,86 @@ void PCA9685_SetPWMFrequency(uint16_t frequency)
// internal 25 MHz oscillator as in the datasheet page no 1/52
else prescale = 25000000 / (4096 * frequency);
// prescale changes 3 to 255 for 1526Hz to 24Hz as in the datasheet page no 1/52
PCA9685_SetBit(PCA9685_MODE1, PCA9685_MODE1_SLEEP_BIT, 1);
HAL_I2C_Mem_Write(&hi2c1, PCA9685_ADDRESS, PCA9685_PRE_SCALE, 1, &prescale, 1, 10);
PCA9685_SetBit(PCA9685_MODE1, PCA9685_MODE1_SLEEP_BIT, 0);
PCA9685_SetBit(PCA9685_MODE1, PCA9685_MODE1_RESTART_BIT, 1);
PCA9685_SetBit(Address, PCA9685_MODE1, PCA9685_MODE1_SLEEP_BIT, 1);
HAL_I2C_Mem_Write(&hi2c1, Address, PCA9685_PRE_SCALE, 1, &prescale, 1, 10);
PCA9685_SetBit(Address, PCA9685_MODE1, PCA9685_MODE1_SLEEP_BIT, 0);
PCA9685_SetBit(Address, PCA9685_MODE1, PCA9685_MODE1_RESTART_BIT, 1);
}
void PCA9685_Init(uint16_t frequency)
void PCA9685_Init(uint8_t Address, uint16_t frequency)
{
PCA9685_SetPWMFrequency(frequency); // 50 Hz for servo
PCA9685_SetBit(PCA9685_MODE1, PCA9685_MODE1_AI_BIT, 1);
PCA9685_SetPWMFrequency(Address, frequency); // 50 Hz for servo
PCA9685_SetBit(Address, PCA9685_MODE1, PCA9685_MODE1_AI_BIT, 1);
}
void PCA9685_SetPWM(uint8_t Channel, uint16_t OnTime, uint16_t OffTime)
void PCA9685_InitAllBoards(uint16_t frequency)
{
for (uint8_t i = 0; i < PCA9685_COUNT; i++) {
PCA9685_Init(PCA9685_BASE_ADDR + i, frequency);
}
}
void PCA9685_SetPWM(uint8_t Address, uint8_t Channel, uint16_t OnTime, uint16_t OffTime)
{
uint8_t registerAddress;
uint8_t pwm[4];
registerAddress = PCA9685_LED0_ON_L + (4 * Channel);
// See example 1 in the datasheet page no 18/52
pwm[0] = OnTime & 0xFF;
pwm[1] = OnTime>>8;
pwm[2] = OffTime & 0xFF;
pwm[3] = OffTime>>8;
HAL_I2C_Mem_Write(&hi2c1, PCA9685_ADDRESS, registerAddress, 1, pwm, 4, 10);
uint8_t pwm[4] = {
OnTime & 0xFF,
OnTime >> 8,
OffTime & 0xFF,
OffTime >> 8
};
HAL_I2C_Mem_Write(&hi2c1, Address << 1, registerAddress, 1, pwm, 4, 10);
}
void PCA9685_SetServoAngle(uint8_t Channel, float Angle)
{
float Value;
// 50 Hz servo then 4095 Value --> 20 milliseconds
// Centieme de radians
// 0 rad --> 0.5 ms(102.4 Value) and 2 PI radians --> 2.5 ms(511.9 Value)
Value = (Angle * (511.9 - 102.4) / (/*100 **/ 3.141592)) + 102.4;
PCA9685_SetPWM(Channel, 0, (uint16_t)Value);
uint8_t addr, ch;
servo_to_pca(Channel, &addr, &ch);
float pwm = (Angle * (SERVO_MAX_PULSE - SERVO_MIN_PULSE)
/ (float)M_PI) + SERVO_MIN_PULSE;
if (pwm < SERVO_MIN_PULSE) pwm = SERVO_MIN_PULSE;
if (pwm > SERVO_MAX_PULSE) pwm = SERVO_MAX_PULSE;
PCA9685_SetPWM(addr, ch, 0, (uint16_t)pwm);
}
void PCA9685_ContinuousServoRun(uint8_t Channel)
{
PCA9685_SetPWM(Channel, 0, 511);
uint8_t addr, ch;
servo_to_pca(Channel, &addr, &ch);
PCA9685_SetPWM(addr, ch, 0, 511);
}
void PCA9685_ContinuousServoStop(uint8_t Channel)
{
PCA9685_SetPWM(Channel, 0, 307);
uint8_t addr, ch;
servo_to_pca(Channel, &addr, &ch);
PCA9685_SetPWM(addr, ch, 0, 307);
}
void PCA9685_LEDOff(uint8_t Channel)
{
PCA9685_SetPWM(Channel, 0, 0);
uint8_t addr, ch;
servo_to_pca(Channel, &addr, &ch);
PCA9685_SetPWM(addr, ch, 0, 0);
}
void PCA9685_LEDOn(uint8_t Channel)
{
PCA9685_SetPWM(Channel, 0, 1000);
uint8_t addr, ch;
servo_to_pca(Channel, &addr, &ch);
PCA9685_SetPWM(addr, ch, 0, 1000);
}
/* ######################## PARTIE TMC2209 STEPPER ########################### */
@@ -175,7 +222,7 @@ void step(uint32_t steps, uint32_t delay_us)
extern Actionneurs act;
void initActionneurs(){
PCA9685_Init(50);
PCA9685_InitAllBoards(PCA9685_PWM_FREQ);
HAL_GPIO_WritePin(DIR_PORT, DIR_PIN, GPIO_PIN_SET);
TMC2209_init();
act.etatLedArmement = 0;