diff --git a/source/Core/BSP/BSP_PD.h b/source/Core/BSP/BSP_PD.h index ef65a52a..f2c97802 100644 --- a/source/Core/BSP/BSP_PD.h +++ b/source/Core/BSP/BSP_PD.h @@ -8,9 +8,6 @@ #ifndef USER_BSP_PD_H_ #define USER_BSP_PD_H_ #include "BSP.h" -/* - * An array of all of the desired voltages & minimum currents in preferred order - */ -extern const uint16_t USB_PD_Desired_Levels[]; -extern const uint8_t USB_PD_Desired_Levels_Len; +bool getFUS302IRQLow(); // Return true if the IRQ line is still held low + #endif /* USER_BSP_PD_H_ */ diff --git a/source/Core/BSP/Defines.h b/source/Core/BSP/Defines.h index c7b5d9ff..f5a8d841 100644 --- a/source/Core/BSP/Defines.h +++ b/source/Core/BSP/Defines.h @@ -15,4 +15,5 @@ enum Orientation { ORIENTATION_LEFT_HAND = 0, ORIENTATION_RIGHT_HAND = 1, ORIENT #define TICKS_SECOND configTICK_RATE_HZ #define TICKS_MIN (60 * TICKS_SECOND) #define TICKS_100MS (TICKS_SECOND / 10) +#define TICKS_10MS (TICKS_100MS / 10) #endif /* BSP_DEFINES_H_ */ diff --git a/source/Core/BSP/Miniware/BSP_PD.c b/source/Core/BSP/Miniware/BSP_PD.c deleted file mode 100644 index 0083caeb..00000000 --- a/source/Core/BSP/Miniware/BSP_PD.c +++ /dev/null @@ -1,22 +0,0 @@ -/* - * BSP_PD.c - * - * Created on: 21 Jul 2020 - * Author: Ralim - */ - -#include "BSP_PD.h" -#include "Model_Config.h" -#ifdef POW_PD -/* - * An array of all of the desired voltages & minimum currents in preferred order - */ -const uint16_t USB_PD_Desired_Levels[] = { - // mV desired input, mA minimum required current - 12000, 2400, // 12V @ 2.4A - 9000, 2000, // 9V @ 2A - 5000, 100, // 5V @ whatever - -}; -const uint8_t USB_PD_Desired_Levels_Len = 3; -#endif diff --git a/source/Core/BSP/Miniware/IRQ.cpp b/source/Core/BSP/Miniware/IRQ.cpp index 5a5ffd0e..5afa4bf1 100644 --- a/source/Core/BSP/Miniware/IRQ.cpp +++ b/source/Core/BSP/Miniware/IRQ.cpp @@ -6,7 +6,9 @@ */ #include "IRQ.h" +#include "Pins.h" #include "int_n.h" + /* * Catch the IRQ that says that the conversion is done on the temperature * readings coming in Once these have come in we can unblock the PID so that it @@ -32,3 +34,12 @@ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { (void)GPIO_Pin; InterruptHandler::irqCallback(); } + +bool getFUS302IRQLow() { +#ifdef POW_PD + // Return true if the IRQ line is still held low + return HAL_GPIO_ReadPin(INT_PD_GPIO_Port, INT_PD_Pin) == GPIO_PIN_RESET; +#else + return false; +#endif +} \ No newline at end of file diff --git a/source/Core/BSP/Miniware/Power.cpp b/source/Core/BSP/Miniware/Power.cpp index f2f23534..27384a2c 100644 --- a/source/Core/BSP/Miniware/Power.cpp +++ b/source/Core/BSP/Miniware/Power.cpp @@ -8,10 +8,12 @@ #include "int_n.h" #include "policy_engine.h" bool FUSB302_present = false; +bool FUSB302_probed = false; void power_check() { #ifdef POW_PD if (FUSB302_present) { + PolicyEngine::PPSTimerCallback(); // Cant start QC until either PD works or fails if (PolicyEngine::setupCompleteOrTimedOut() == false) { return; @@ -27,7 +29,12 @@ void power_check() { } uint8_t usb_pd_detect() { #ifdef POW_PD - FUSB302_present = fusb302_detect(); + if (FUSB302_probed) { + return FUSB302_present; + } else { + FUSB302_present = fusb302_detect(); + FUSB302_probed = true; + } return FUSB302_present; #endif return false; diff --git a/source/Core/BSP/Miniware/fusb302b.cpp b/source/Core/BSP/Miniware/fusb302b.cpp deleted file mode 100644 index dbb218b9..00000000 --- a/source/Core/BSP/Miniware/fusb302b.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* - * PD Buddy Firmware Library - USB Power Delivery for everyone - * Copyright 2017-2018 Clayton G. Hobbs - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "Model_Config.h" -#ifdef POW_PD -#include "BSP.h" -#include "I2CBB.hpp" -#include "fusb302b.h" -#include "int_n.h" -#include -/* - * Read a single byte from the FUSB302B - * - * cfg: The FUSB302B to communicate with - * addr: The memory address from which to read - * - * Returns the value read from addr. - */ -static uint8_t fusb_read_byte(uint8_t addr) { - uint8_t data[1]; - if (!I2CBB::Mem_Read(FUSB302B_ADDR, addr, (uint8_t *)data, 1)) { - return 0; - } - return data[0]; -} - -/* - * Read multiple bytes from the FUSB302B - * - * cfg: The FUSB302B to communicate with - * addr: The memory address from which to read - * size: The number of bytes to read - * buf: The buffer into which data will be read - */ -static bool fusb_read_buf(uint8_t addr, uint8_t size, uint8_t *buf) { return I2CBB::Mem_Read(FUSB302B_ADDR, addr, buf, size); } - -/* - * Write a single byte to the FUSB302B - * - * cfg: The FUSB302B to communicate with - * addr: The memory address to which we will write - * byte: The value to write - */ -static bool fusb_write_byte(uint8_t addr, uint8_t byte) { return I2CBB::Mem_Write(FUSB302B_ADDR, addr, (uint8_t *)&byte, 1); } - -/* - * Write multiple bytes to the FUSB302B - * - * cfg: The FUSB302B to communicate with - * addr: The memory address to which we will write - * size: The number of bytes to write - * buf: The buffer to write - */ -static bool fusb_write_buf(uint8_t addr, uint8_t size, const uint8_t *buf) { return I2CBB::Mem_Write(FUSB302B_ADDR, addr, buf, size); } - -void fusb_send_message(const union pd_msg *msg) { - if (!I2CBB::lock2()) { - return; - } - /* Token sequences for the FUSB302B */ - static uint8_t sop_seq[5] = {FUSB_FIFO_TX_SOP1, FUSB_FIFO_TX_SOP1, FUSB_FIFO_TX_SOP1, FUSB_FIFO_TX_SOP2, FUSB_FIFO_TX_PACKSYM}; - static const uint8_t eop_seq[4] = {FUSB_FIFO_TX_JAM_CRC, FUSB_FIFO_TX_EOP, FUSB_FIFO_TX_TXOFF, FUSB_FIFO_TX_TXON}; - - /* Take the I2C2 mutex now so there can't be a race condition on sop_seq */ - /* Get the length of the message: a two-octet header plus NUMOBJ four-octet - * data objects */ - uint8_t msg_len = 2 + 4 * PD_NUMOBJ_GET(msg); - - /* Set the number of bytes to be transmitted in the packet */ - sop_seq[4] = FUSB_FIFO_TX_PACKSYM | msg_len; - - /* Write all three parts of the message to the TX FIFO */ - fusb_write_buf(FUSB_FIFOS, 5, sop_seq); - fusb_write_buf(FUSB_FIFOS, msg_len, msg->bytes); - fusb_write_buf(FUSB_FIFOS, 4, eop_seq); - - I2CBB::unlock2(); -} - -uint8_t fusb_read_message(union pd_msg *msg) { - if (!I2CBB::lock2()) { - asm("bkpt"); - } - static uint8_t garbage[4]; - uint8_t numobj; - - // Read the header. If its not a SOP we dont actually want it at all - // But on some revisions of the fusb if you dont both pick them up and read them out of the fifo, it gets stuck - fusb_read_byte(FUSB_FIFOS); - /* Read the message header into msg */ - fusb_read_buf(FUSB_FIFOS, 2, msg->bytes); - /* Get the number of data objects */ - numobj = PD_NUMOBJ_GET(msg); - /* If there is at least one data object, read the data objects */ - if (numobj > 0) { - fusb_read_buf(FUSB_FIFOS, numobj * 4, msg->bytes + 2); - } - /* Throw the CRC32 in the garbage, since the PHY already checked it. */ - fusb_read_buf(FUSB_FIFOS, 4, garbage); - - I2CBB::unlock2(); - return 0; -} - -void fusb_send_hardrst() { - - if (!I2CBB::lock2()) { - return; - } - /* Send a hard reset */ - fusb_write_byte(FUSB_CONTROL3, 0x07 | FUSB_CONTROL3_SEND_HARD_RESET); - - I2CBB::unlock2(); -} - -bool fusb_setup() { - - if (!I2CBB::lock2()) { - return false; - } - /* Fully reset the FUSB302B */ - // fusb_write_byte( FUSB_RESET, FUSB_RESET_SW_RES); - // osDelay(2); - if (!fusb_read_id()) { - return false; - } - - /* Turn on all power */ - fusb_write_byte(FUSB_POWER, 0x0F); - - /* Set interrupt masks */ - // Setting to 0 so interrupts are allowed - fusb_write_byte(FUSB_MASK1, 0x00); - fusb_write_byte(FUSB_MASKA, 0x00); - fusb_write_byte(FUSB_MASKB, 0x00); - fusb_write_byte(FUSB_CONTROL0, 0b11 << 2); - - /* Enable automatic retransmission */ - fusb_write_byte(FUSB_CONTROL3, 0x07); - // set defaults - fusb_write_byte(FUSB_CONTROL2, 0x00); - /* Flush the RX buffer */ - fusb_write_byte(FUSB_CONTROL1, FUSB_CONTROL1_RX_FLUSH); - - /* Measure CC1 */ - fusb_write_byte(FUSB_SWITCHES0, 0x07); - osDelay(10); - uint8_t cc1 = fusb_read_byte(FUSB_STATUS0) & FUSB_STATUS0_BC_LVL; - - /* Measure CC2 */ - fusb_write_byte(FUSB_SWITCHES0, 0x0B); - osDelay(10); - uint8_t cc2 = fusb_read_byte(FUSB_STATUS0) & FUSB_STATUS0_BC_LVL; - - /* Select the correct CC line for BMC signaling; also enable AUTO_CRC */ - if (cc1 > cc2) { - fusb_write_byte(FUSB_SWITCHES1, 0x25); - fusb_write_byte(FUSB_SWITCHES0, 0x07); - } else { - fusb_write_byte(FUSB_SWITCHES1, 0x26); - fusb_write_byte(FUSB_SWITCHES0, 0x0B); - } - I2CBB::unlock2(); - fusb_reset(); - GPIO_InitTypeDef GPIO_InitStruct; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.Pin = GPIO_PIN_9; - GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; - GPIO_InitStruct.Pull = GPIO_PULLUP; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - HAL_NVIC_SetPriority(EXTI9_5_IRQn, 10, 0); - HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); - return true; -} - -void fusb_get_status(union fusb_status *status) { - if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { - if (!I2CBB::lock2()) { - return; - } - } - - /* Read the interrupt and status flags into status */ - fusb_read_buf(FUSB_STATUS0A, 7, status->bytes); - if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { - I2CBB::unlock2(); - } -} - -enum fusb_typec_current fusb_get_typec_current() { - if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { - if (!I2CBB::lock2()) { - return fusb_tcc_none; - } - } - /* Read the BC_LVL into a variable */ - enum fusb_typec_current bc_lvl = (enum fusb_typec_current)(fusb_read_byte(FUSB_STATUS0) & FUSB_STATUS0_BC_LVL); - if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { - I2CBB::unlock2(); - } - return bc_lvl; -} - -void fusb_reset() { - if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { - if (!I2CBB::lock2()) { - return; - } - } - - /* Flush the TX buffer */ - fusb_write_byte(FUSB_CONTROL0, 0x44); - /* Flush the RX buffer */ - fusb_write_byte(FUSB_CONTROL1, FUSB_CONTROL1_RX_FLUSH); - if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { - I2CBB::unlock2(); - } -} - -bool fusb_read_id() { - // Return true if read of the revision ID is sane - uint8_t version = 0; - fusb_read_buf(FUSB_DEVICE_ID, 1, &version); - if (version == 0 || version == 0xFF) - return false; - return true; -} -uint8_t fusb302_detect() { - // Probe the I2C bus for its address - return I2CBB::probe(FUSB302B_ADDR); -} - -#endif diff --git a/source/Core/BSP/Miniware/fusb_user.cpp b/source/Core/BSP/Miniware/fusb_user.cpp new file mode 100644 index 00000000..5ae87423 --- /dev/null +++ b/source/Core/BSP/Miniware/fusb_user.cpp @@ -0,0 +1,68 @@ +#include "Model_Config.h" +#ifdef POW_PD +#include "BSP.h" +#include "I2CBB.hpp" +#include "Setup.h" +#include "fusb302b.h" +#include "fusb_user.h" +/* + * Read a single byte from the FUSB302B + * + * cfg: The FUSB302B to communicate with + * addr: The memory address from which to read + * + * Returns the value read from addr. + */ +uint8_t fusb_read_byte(uint8_t addr) { + uint8_t data[1]; + if (!I2CBB::Mem_Read(FUSB302B_ADDR, addr, (uint8_t *)data, 1)) { + return 0; + } + return data[0]; +} + +/* + * Read multiple bytes from the FUSB302B + * + * cfg: The FUSB302B to communicate with + * addr: The memory address from which to read + * size: The number of bytes to read + * buf: The buffer into which data will be read + */ +bool fusb_read_buf(uint8_t addr, uint8_t size, uint8_t *buf) { return I2CBB::Mem_Read(FUSB302B_ADDR, addr, buf, size); } + +/* + * Write a single byte to the FUSB302B + * + * cfg: The FUSB302B to communicate with + * addr: The memory address to which we will write + * byte: The value to write + */ +bool fusb_write_byte(uint8_t addr, uint8_t byte) { return I2CBB::Mem_Write(FUSB302B_ADDR, addr, (uint8_t *)&byte, 1); } + +/* + * Write multiple bytes to the FUSB302B + * + * cfg: The FUSB302B to communicate with + * addr: The memory address to which we will write + * size: The number of bytes to write + * buf: The buffer to write + */ +bool fusb_write_buf(uint8_t addr, uint8_t size, const uint8_t *buf) { return I2CBB::Mem_Write(FUSB302B_ADDR, addr, buf, size); } + +uint8_t fusb302_detect() { + // Probe the I2C bus for its address + return I2CBB::probe(FUSB302B_ADDR); +} + +void setupFUSBIRQ() { + GPIO_InitTypeDef GPIO_InitStruct; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Pin = GPIO_PIN_9; + GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; + GPIO_InitStruct.Pull = GPIO_PULLUP; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + HAL_NVIC_SetPriority(EXTI9_5_IRQn, 10, 0); + HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); +} +#endif diff --git a/source/Core/BSP/Miniware/postRTOS.cpp b/source/Core/BSP/Miniware/postRTOS.cpp index 34cd8e33..2daab8b6 100644 --- a/source/Core/BSP/Miniware/postRTOS.cpp +++ b/source/Core/BSP/Miniware/postRTOS.cpp @@ -11,11 +11,4 @@ #include "task.h" // Initialisation to be performed with scheduler active -void postRToSInit() { -#ifdef POW_PD - if (usb_pd_detect() == true) { - // Spawn all of the USB-C processors - fusb302_start_processing(); - } -#endif -} +void postRToSInit() {} diff --git a/source/Core/BSP/Pine64/BSP_PD.c b/source/Core/BSP/Pine64/BSP_PD.c deleted file mode 100644 index 8608c814..00000000 --- a/source/Core/BSP/Pine64/BSP_PD.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * BSP_PD.c - * - * Created on: 21 Jul 2020 - * Author: Ralim - */ - -#include "BSP_PD.h" -#include "Model_Config.h" -#ifdef POW_PD -/* - * An array of all of the desired voltages & minimum currents in preferred order - */ -const uint16_t USB_PD_Desired_Levels[] = { - // mV desired input, mA minimum required current - // Tip is ~ 7.5 ohms - 20000, 2666, // 20V, 2.6A - 18000, 2400, // 18V, 2.4A - 15000, 2000, // 15V 2A - 12000, 1600, // 12V @ 1.6A - 9000, 1200, // 9V @ 1.2A - 5000, 100, // 5V @ whatever - -}; -const uint8_t USB_PD_Desired_Levels_Len = 6; -#endif diff --git a/source/Core/BSP/Pine64/IRQ.cpp b/source/Core/BSP/Pine64/IRQ.cpp index 1a3be266..9285bb16 100644 --- a/source/Core/BSP/Pine64/IRQ.cpp +++ b/source/Core/BSP/Pine64/IRQ.cpp @@ -118,6 +118,10 @@ void EXTI5_9_IRQHandler(void) { #endif } +bool getFUS302IRQLow() { + // Return true if the IRQ line is still held low + return (RESET == gpio_input_bit_get(FUSB302_IRQ_GPIO_Port, FUSB302_IRQ_Pin)); +} // These are unused for now void I2C0_EV_IRQHandler(void) {} diff --git a/source/Core/BSP/Pine64/Power.cpp b/source/Core/BSP/Pine64/Power.cpp index c7d18a6e..540d757e 100644 --- a/source/Core/BSP/Pine64/Power.cpp +++ b/source/Core/BSP/Pine64/Power.cpp @@ -8,10 +8,12 @@ #include "int_n.h" #include "policy_engine.h" bool FUSB302_present = false; +bool FUSB302_probed = false; void power_check() { #ifdef POW_PD if (FUSB302_present) { + PolicyEngine::PPSTimerCallback(); // Cant start QC until either PD works or fails if (PolicyEngine::setupCompleteOrTimedOut() == false) { return; @@ -27,8 +29,12 @@ void power_check() { } uint8_t usb_pd_detect() { #ifdef POW_PD - FUSB302_present = fusb302_detect(); - + if (FUSB302_probed) { + return FUSB302_present; + } else { + FUSB302_present = fusb302_detect(); + FUSB302_probed = true; + } return FUSB302_present; #endif return false; diff --git a/source/Core/BSP/Pine64/fusb_user.cpp b/source/Core/BSP/Pine64/fusb_user.cpp new file mode 100644 index 00000000..bc62bc62 --- /dev/null +++ b/source/Core/BSP/Pine64/fusb_user.cpp @@ -0,0 +1,58 @@ +#include "Model_Config.h" +#ifdef POW_PD +#include "BSP.h" +#include "I2C_Wrapper.hpp" +#include "Setup.h" +#include "fusb302b.h" +#include "fusb_user.h" +/* + * Read a single byte from the FUSB302B + * + * cfg: The FUSB302B to communicate with + * addr: The memory address from which to read + * + * Returns the value read from addr. + */ +uint8_t fusb_read_byte(uint8_t addr) { + uint8_t data[1]; + if (!FRToSI2C::Mem_Read(FUSB302B_ADDR, addr, (uint8_t *)data, 1)) { + return 0; + } + return data[0]; +} + +/* + * Read multiple bytes from the FUSB302B + * + * cfg: The FUSB302B to communicate with + * addr: The memory address from which to read + * size: The number of bytes to read + * buf: The buffer into which data will be read + */ +bool fusb_read_buf(uint8_t addr, uint8_t size, uint8_t *buf) { return FRToSI2C::Mem_Read(FUSB302B_ADDR, addr, buf, size); } + +/* + * Write a single byte to the FUSB302B + * + * cfg: The FUSB302B to communicate with + * addr: The memory address to which we will write + * byte: The value to write + */ +bool fusb_write_byte(uint8_t addr, uint8_t byte) { return FRToSI2C::Mem_Write(FUSB302B_ADDR, addr, (uint8_t *)&byte, 1); } + +/* + * Write multiple bytes to the FUSB302B + * + * cfg: The FUSB302B to communicate with + * addr: The memory address to which we will write + * size: The number of bytes to write + * buf: The buffer to write + */ +bool fusb_write_buf(uint8_t addr, uint8_t size, const uint8_t *buf) { return FRToSI2C::Mem_Write(FUSB302B_ADDR, addr, (uint8_t *)buf, size); } + +uint8_t fusb302_detect() { + // Probe the I2C bus for its address + return FRToSI2C::probe(FUSB302B_ADDR); +} + +#endif diff --git a/source/Core/BSP/Pine64/postRTOS.cpp b/source/Core/BSP/Pine64/postRTOS.cpp index 0d684f3f..107d2597 100644 --- a/source/Core/BSP/Pine64/postRTOS.cpp +++ b/source/Core/BSP/Pine64/postRTOS.cpp @@ -19,10 +19,6 @@ void postRToSInit() { hall_effect_present = Si7210::init(); } #endif -#ifdef POW_PD - // Spawn all of the USB-C processors - fusb302_start_processing(); -#endif } int16_t getRawHallEffect() { if (hall_effect_present) { diff --git a/source/Core/BSP/Pine64/fusb302b.cpp b/source/Core/Drivers/FUSB302/fusb302b.cpp similarity index 73% rename from source/Core/BSP/Pine64/fusb302b.cpp rename to source/Core/Drivers/FUSB302/fusb302b.cpp index ee2f5e9e..63ef5baf 100644 --- a/source/Core/BSP/Pine64/fusb302b.cpp +++ b/source/Core/Drivers/FUSB302/fusb302b.cpp @@ -14,65 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "Model_Config.h" -#ifdef POW_PD +#include "fusb302b.h" #include "BSP.h" #include "I2C_Wrapper.hpp" #include "Setup.h" -#include "fusb302b.h" +#include "fusb_user.h" #include "int_n.h" #include -/* - * Read a single byte from the FUSB302B - * - * cfg: The FUSB302B to communicate with - * addr: The memory address from which to read - * - * Returns the value read from addr. - */ -static uint8_t fusb_read_byte(uint8_t addr) { - uint8_t data[1]; - if (!FRToSI2C::Mem_Read(FUSB302B_ADDR, addr, (uint8_t *)data, 1)) { - return 0; - } - return data[0]; -} - -/* - * Read multiple bytes from the FUSB302B - * - * cfg: The FUSB302B to communicate with - * addr: The memory address from which to read - * size: The number of bytes to read - * buf: The buffer into which data will be read - */ -static bool fusb_read_buf(uint8_t addr, uint8_t size, uint8_t *buf) { return FRToSI2C::Mem_Read(FUSB302B_ADDR, addr, buf, size); } - -/* - * Write a single byte to the FUSB302B - * - * cfg: The FUSB302B to communicate with - * addr: The memory address to which we will write - * byte: The value to write - */ -static bool fusb_write_byte(uint8_t addr, uint8_t byte) { - FRToSI2C::Mem_Write(FUSB302B_ADDR, addr, (uint8_t *)&byte, 1); - return true; -} - -/* - * Write multiple bytes to the FUSB302B - * - * cfg: The FUSB302B to communicate with - * addr: The memory address to which we will write - * size: The number of bytes to write - * buf: The buffer to write - */ -static bool fusb_write_buf(uint8_t addr, uint8_t size, const uint8_t *buf) { - FRToSI2C::Mem_Write(FUSB302B_ADDR, addr, (uint8_t *)buf, size); - return true; // TODO -} - void fusb_send_message(const union pd_msg *msg) { /* Token sequences for the FUSB302B */ @@ -122,15 +70,12 @@ void fusb_send_hardrst() { } bool fusb_setup() { - if (!FRToSI2C::probe(FUSB302B_ADDR)) { - return false; - } /* Fully reset the FUSB302B */ fusb_write_byte(FUSB_RESET, FUSB_RESET_SW_RES); - osDelay(2); + vTaskDelay(TICKS_10MS); uint8_t tries = 0; while (!fusb_read_id()) { - osDelay(10); + vTaskDelay(TICKS_10MS); tries++; if (tries > 5) { return false; // Welp :( @@ -156,12 +101,12 @@ bool fusb_setup() { /* Measure CC1 */ fusb_write_byte(FUSB_SWITCHES0, 0x07); - osDelay(10); + vTaskDelay(TICKS_10MS); uint8_t cc1 = fusb_read_byte(FUSB_STATUS0) & FUSB_STATUS0_BC_LVL; /* Measure CC2 */ fusb_write_byte(FUSB_SWITCHES0, 0x0B); - osDelay(10); + vTaskDelay(TICKS_10MS); uint8_t cc2 = fusb_read_byte(FUSB_STATUS0) & FUSB_STATUS0_BC_LVL; /* Select the correct CC line for BMC signaling; also enable AUTO_CRC */ @@ -209,10 +154,4 @@ bool fusb_read_id() { if (version == 0 || version == 0xFF) return false; return true; -} -uint8_t fusb302_detect() { - // Probe the I2C bus for its address - return FRToSI2C::probe(FUSB302B_ADDR); -} - -#endif +} \ No newline at end of file diff --git a/source/Core/Drivers/FUSB302/fusb_user.h b/source/Core/Drivers/FUSB302/fusb_user.h new file mode 100644 index 00000000..9a81c611 --- /dev/null +++ b/source/Core/Drivers/FUSB302/fusb_user.h @@ -0,0 +1,29 @@ +/* + * PD Buddy Firmware Library - USB Power Delivery for everyone + * Copyright 2017-2018 Clayton G. Hobbs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PDB_FUSB_USER_H +#define PDB_FUSB_USER_H + +#include +uint8_t fusb_read_byte(uint8_t addr); +bool fusb_read_buf(uint8_t addr, uint8_t size, uint8_t *buf); +bool fusb_write_byte(uint8_t addr, uint8_t byte); +bool fusb_write_buf(uint8_t addr, uint8_t size, const uint8_t *buf); +uint8_t fusb302_detect(); +void setupFUSBIRQ(); + +#endif /* PDB_FUSB302B_H */ diff --git a/source/Core/Drivers/FUSB302/fusbpd.cpp b/source/Core/Drivers/FUSB302/fusbpd.cpp index 56539f28..54f026c0 100644 --- a/source/Core/Drivers/FUSB302/fusbpd.cpp +++ b/source/Core/Drivers/FUSB302/fusbpd.cpp @@ -11,7 +11,7 @@ #include "fusb302b.h" #include "int_n.h" #include "policy_engine.h" -#include "protocol_rx.h" + #include "protocol_tx.h" #include #include @@ -21,7 +21,6 @@ void fusb302_start_processing() { if (fusb_setup()) { PolicyEngine::init(); ProtocolTransmit::init(); - ProtocolReceive::init(); InterruptHandler::init(); } } diff --git a/source/Core/Drivers/FUSB302/int_n.cpp b/source/Core/Drivers/FUSB302/int_n.cpp index 892dbfe2..1ca67894 100644 --- a/source/Core/Drivers/FUSB302/int_n.cpp +++ b/source/Core/Drivers/FUSB302/int_n.cpp @@ -17,34 +17,63 @@ #include "int_n.h" #include "BSP.h" +#include "BSP_PD.h" #include "fusb302b.h" #include "fusbpd.h" #include "policy_engine.h" -#include "protocol_rx.h" + #include "protocol_tx.h" #include "task.h" #include +#include -osThreadId InterruptHandler::TaskHandle = NULL; +volatile osThreadId InterruptHandler::TaskHandle = NULL; uint32_t InterruptHandler::TaskBuffer[InterruptHandler::TaskStackSize]; osStaticThreadDef_t InterruptHandler::TaskControlBlock; +union pd_msg InterruptHandler::tempMessage; void InterruptHandler::init() { + TaskHandle = NULL; osThreadStaticDef(intTask, Thread, PDB_PRIO_PRL_INT_N, 0, TaskStackSize, TaskBuffer, &TaskControlBlock); TaskHandle = osThreadCreate(osThread(intTask), NULL); } +void InterruptHandler::readPendingMessage() { + /* Get a buffer to read the message into. Guaranteed to not fail + * because we have a big enough pool and are careful. */ + memset(&tempMessage, 0, sizeof(tempMessage)); + /* Read the message */ + fusb_read_message(&tempMessage); + /* If it's a Soft_Reset, go to the soft reset state */ + if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SOFT_RESET && PD_NUMOBJ_GET(&tempMessage) == 0) { + /* TX transitions to its reset state */ + ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_RESET); + } else { + /* Tell ProtocolTX to discard the message being transmitted */ + ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_DISCARD); + + /* Pass the message to the policy engine. */ + PolicyEngine::handleMessage(&tempMessage); + } +} + void InterruptHandler::Thread(const void *arg) { (void)arg; union fusb_status status; - while (true) { - /* If the INT_N line is low */ - if (xTaskNotifyWait(0x00, 0x0F, NULL, PolicyEngine::setupCompleteOrTimedOut() ? 1000 : 10) == pdPASS) { - // delay slightly so we catch the crc with better timing - osDelay(1); + for (;;) { + // If the irq is low continue, otherwise wait for irq or timeout + if (!getFUS302IRQLow()) { + xTaskNotifyWait(0x00, 0x0F, NULL, TICKS_SECOND * 30); } /* Read the FUSB302B status and interrupt registers */ fusb_get_status(&status); + + /* If the I_GCRCSENT flag is set, tell the Protocol RX thread */ + // This means a message was recieved with a good CRC + if (status.interruptb & FUSB_INTERRUPTB_I_GCRCSENT) { + readPendingMessage(); + } + /* If the I_TXSENT or I_RETRYFAIL flag is set, tell the Protocol TX * thread */ if (status.interrupta & FUSB_INTERRUPTA_I_TXSENT) { @@ -54,25 +83,17 @@ void InterruptHandler::Thread(const void *arg) { ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_I_RETRYFAIL); } - /* If the I_GCRCSENT flag is set, tell the Protocol RX thread */ - // This means a message was recieved with a good CRC - if (status.interruptb & FUSB_INTERRUPTB_I_GCRCSENT) { - ProtocolReceive::notify(PDB_EVT_PRLRX_I_GCRCSENT); - } - /* If the I_OCP_TEMP and OVRTEMP flags are set, tell the Policy * Engine thread */ if ((status.interrupta & FUSB_INTERRUPTA_I_OCP_TEMP) && (status.status1 & FUSB_STATUS1_OVRTEMP)) { - PolicyEngine::notify(PDB_EVT_PE_I_OVRTEMP); + PolicyEngine::notify(PolicyEngine::Notifications::PDB_EVT_PE_I_OVRTEMP); } } } void InterruptHandler::irqCallback() { - if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { - if (TaskHandle != NULL) { - BaseType_t taskWoke = pdFALSE; - xTaskNotifyFromISR(TaskHandle, 0x01, eNotifyAction::eSetBits, &taskWoke); - portYIELD_FROM_ISR(taskWoke); - } + if (TaskHandle != NULL) { + BaseType_t taskWoke = pdFALSE; + xTaskNotifyFromISR(TaskHandle, 0x01, eNotifyAction::eSetBits, &taskWoke); + portYIELD_FROM_ISR(taskWoke); } } diff --git a/source/Core/Drivers/FUSB302/int_n.h b/source/Core/Drivers/FUSB302/int_n.h index 4b291a5e..ed18b50d 100644 --- a/source/Core/Drivers/FUSB302/int_n.h +++ b/source/Core/Drivers/FUSB302/int_n.h @@ -29,7 +29,7 @@ public: private: static void Thread(const void *arg); - static osThreadId TaskHandle; + static volatile osThreadId TaskHandle; static const size_t TaskStackSize = 1536 / 3; static uint32_t TaskBuffer[TaskStackSize]; static osStaticThreadDef_t TaskControlBlock; @@ -44,6 +44,9 @@ private: static enum hardrst_state hardrst_hard_reset_requested(); static enum hardrst_state hardrst_wait_pe(); static enum hardrst_state hardrst_complete(); + // Mesage rx + static void readPendingMessage(); + static union pd_msg tempMessage; }; #endif /* PDB_INT_N_OLD_H */ diff --git a/source/Core/Drivers/FUSB302/pd.h b/source/Core/Drivers/FUSB302/pd.h index 5907f26f..bdf3fa36 100644 --- a/source/Core/Drivers/FUSB302/pd.h +++ b/source/Core/Drivers/FUSB302/pd.h @@ -271,13 +271,13 @@ * Where a range is specified, the middle of the range (rounded down to the * nearest millisecond) is used. */ -#define PD_T_CHUNKING_NOT_SUPPORTED (450) -#define PD_T_HARD_RESET_COMPLETE (1000) -#define PD_T_PS_TRANSITION (5000) -#define PD_T_SENDER_RESPONSE (2700) -#define PD_T_SINK_REQUEST (1000) -#define PD_T_TYPEC_SINK_WAIT_CAP (1000) -#define PD_T_PD_DEBOUNCE (2000) +#define PD_T_CHUNKING_NOT_SUPPORTED (TICKS_SECOND / 2) +#define PD_T_HARD_RESET_COMPLETE (1 * TICKS_SECOND) +#define PD_T_PS_TRANSITION (5 * TICKS_SECOND) +#define PD_T_SENDER_RESPONSE (27 * TICKS_100MS) +#define PD_T_SINK_REQUEST (1 * TICKS_SECOND) +#define PD_T_TYPEC_SINK_WAIT_CAP (1 * TICKS_SECOND) +#define PD_T_PD_DEBOUNCE (2 * TICKS_SECOND) /* * Counter maximums diff --git a/source/Core/Drivers/FUSB302/pdb_conf.h b/source/Core/Drivers/FUSB302/pdb_conf.h index fc1e4188..7e50295f 100644 --- a/source/Core/Drivers/FUSB302/pdb_conf.h +++ b/source/Core/Drivers/FUSB302/pdb_conf.h @@ -19,13 +19,13 @@ #define PDB_CONF_H /* Number of messages in the message pool */ -#define PDB_MSG_POOL_SIZE 4 +#define PDB_MSG_POOL_SIZE 8 #define EVENT_MASK(x) (1 << x) -#define eventmask_t uint32_t + /* PD Buddy thread priorities */ -#define PDB_PRIO_PE (osPriorityNormal) -#define PDB_PRIO_PRL (osPriorityBelowNormal) -#define PDB_PRIO_PRL_INT_N (osPriorityLow) +#define PDB_PRIO_PE (osPriorityAboveNormal) +#define PDB_PRIO_PRL (osPriorityAboveNormal) +#define PDB_PRIO_PRL_INT_N (osPriorityAboveNormal) #endif /* PDB_CONF_H */ diff --git a/source/Core/Drivers/FUSB302/policy_engine.cpp b/source/Core/Drivers/FUSB302/policy_engine.cpp index 2ab7f99a..d1ebaba0 100644 --- a/source/Core/Drivers/FUSB302/policy_engine.cpp +++ b/source/Core/Drivers/FUSB302/policy_engine.cpp @@ -16,6 +16,7 @@ */ #include "policy_engine.h" +#include "Defines.h" #include "fusb302b.h" #include "int_n.h" #include "protocol_tx.h" @@ -31,7 +32,6 @@ bool PolicyEngine::_explicit_contract; int8_t PolicyEngine::_hard_reset_counter; int8_t PolicyEngine::_old_tcc_match; uint8_t PolicyEngine::_pps_index; -uint8_t PolicyEngine::_last_pps; osThreadId PolicyEngine::TaskHandle = NULL; uint32_t PolicyEngine::TaskBuffer[PolicyEngine::TaskStackSize]; osStaticThreadDef_t PolicyEngine::TaskControlBlock; @@ -43,6 +43,8 @@ uint8_t PolicyEngine::ucQueueStorageArea[PDB_MSG_POOL_ QueueHandle_t PolicyEngine::messagesWaiting = NULL; EventGroupHandle_t PolicyEngine::xEventGroupHandle = NULL; StaticEventGroup_t PolicyEngine::xCreatedEventGroup; +bool PolicyEngine::PPSTimerEnabled = false; +TickType_t PolicyEngine::PPSTimeLastEvent = 0; void PolicyEngine::init() { messagesWaiting = xQueueCreateStatic(PDB_MSG_POOL_SIZE, sizeof(union pd_msg), ucQueueStorageArea, &xStaticQueue); // Create static thread at PDB_PRIO_PE priority @@ -51,9 +53,10 @@ void PolicyEngine::init() { xEventGroupHandle = xEventGroupCreateStatic(&xCreatedEventGroup); } -void PolicyEngine::notify(uint32_t notification) { +void PolicyEngine::notify(PolicyEngine::Notifications notification) { + EventBits_t val = (EventBits_t)notification; if (xEventGroupHandle != NULL) { - xEventGroupSetBits(xEventGroupHandle, notification); + xEventGroupSetBits(xEventGroupHandle, val); } } @@ -64,9 +67,7 @@ void PolicyEngine::pe_task(const void *arg) { /* Initialize the old_tcc_match */ _old_tcc_match = -1; /* Initialize the pps_index */ - _pps_index = 8; - /* Initialize the last_pps */ - _last_pps = 8; + _pps_index = 0xFF; for (;;) { // Loop based on state @@ -133,7 +134,7 @@ void PolicyEngine::pe_task(const void *arg) { PolicyEngine::policy_engine_state PolicyEngine::pe_sink_startup() { /* We don't have an explicit contract currently */ _explicit_contract = false; - + PPSTimerEnabled = false; // If desired could send an alert that PD is starting /* No need to reset the protocol layer here. There are two ways into this @@ -154,31 +155,27 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_discovery() { PolicyEngine::policy_engine_state PolicyEngine::pe_sink_wait_cap() { /* Fetch a message from the protocol layer */ - eventmask_t evt = 0; - if (readMessage()) { - evt = PDB_EVT_PE_MSG_RX_PEND; - } else { - evt = waitForEvent(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_I_OVRTEMP | PDB_EVT_PE_RESET, - // Wait for cap timeout - PD_T_TYPEC_SINK_WAIT_CAP); - } + EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_MSG_RX | (uint32_t)Notifications::PDB_EVT_PE_I_OVRTEMP | (uint32_t)Notifications::PDB_EVT_PE_RESET, + // Wait for cap timeout + PD_T_TYPEC_SINK_WAIT_CAP); + /* If we timed out waiting for Source_Capabilities, send a hard reset */ if (evt == 0) { return PESinkHardReset; } /* If we got reset signaling, transition to default */ - if (evt & PDB_EVT_PE_RESET) { + if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) { return PESinkWaitCap; } /* If we're too hot, we shouldn't negotiate power yet */ - if (evt & PDB_EVT_PE_I_OVRTEMP) { + if (evt & (uint32_t)Notifications::PDB_EVT_PE_I_OVRTEMP) { return PESinkWaitCap; } /* If we got a message */ - if (evt & (PDB_EVT_PE_MSG_RX | PDB_EVT_PE_MSG_RX_PEND)) { + if (evt & (uint32_t)Notifications::PDB_EVT_PE_MSG_RX) { /* Get the message */ - while ((evt & PDB_EVT_PE_MSG_RX_PEND) || readMessage() == true) { + while (readMessage()) { /* If we got a Source_Capabilities message, read it. */ if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SOURCE_CAPABILITIES && PD_NUMOBJ_GET(&tempMessage) > 0) { /* First, determine what PD revision we're using */ @@ -194,15 +191,13 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_wait_cap() { } } return PESinkEvalCap; - /* If the message was a Soft_Reset, do the soft reset procedure */ } - evt = 0; } return PESinkWaitCap; // wait for more messages? } - /* If we failed to get a message, send a hard reset */ - return PESinkHardReset; + /* If we failed to get a message, wait longer */ + return PESinkWaitCap; } PolicyEngine::policy_engine_state PolicyEngine::pe_sink_eval_cap() { @@ -211,7 +206,9 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_eval_cap() { * PE_SNK_Select_Cap. */ /* Start by assuming we won't find a PPS APDO (set the index greater * than the maximum possible) */ - _pps_index = 8; + _pps_index = 0xFF; + /* New capabilities also means we can't be making a request from the + * same PPS APDO */ /* Search for the first PPS APDO */ for (int i = 0; i < PD_NUMOBJ_GET(&tempMessage); i++) { if ((tempMessage.obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_AUGMENTED && (tempMessage.obj[i] & PD_APDO_TYPE) == PD_APDO_TYPE_PPS) { @@ -219,13 +216,18 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_eval_cap() { break; } } - /* New capabilities also means we can't be making a request from the - * same PPS APDO */ - _last_pps = 8; /* Ask the DPM what to request */ if (pdbs_dpm_evaluate_capability(&tempMessage, &_last_dpm_request)) { - + /* If we're using PD 3.0 */ + if ((hdr_template & PD_HDR_SPECREV) == PD_SPECREV_3_0) { + /* If the request was for a PPS APDO, start time callbacks if not started */ + if (PD_RDO_OBJPOS_GET(&_last_dpm_request) >= _pps_index) { + PPSTimerEnabled = true; + } else { + PPSTimerEnabled = false; + } + } return PESinkSelectCap; } @@ -235,29 +237,28 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_eval_cap() { PolicyEngine::policy_engine_state PolicyEngine::pe_sink_select_cap() { /* Transmit the request */ - waitForEvent(0xFFFF, 0); // clear pending + waitForEvent((uint32_t)Notifications::PDB_EVT_PE_ALL, 0); // clear pending ProtocolTransmit::pushMessage(&_last_dpm_request); // Send indication that there is a message pending - ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_MSG_TX); - eventmask_t evt = waitForEvent(PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET); + EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_TX_DONE | (uint32_t)Notifications::PDB_EVT_PE_TX_ERR | (uint32_t)Notifications::PDB_EVT_PE_RESET); /* If we got reset signaling, transition to default */ - if (evt & PDB_EVT_PE_RESET || evt == 0) { + if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET || evt == 0) { return PESinkTransitionDefault; } /* If the message transmission failed, send a hard reset */ - if ((evt & PDB_EVT_PE_TX_ERR) == PDB_EVT_PE_TX_ERR) { + if ((evt & (uint32_t)Notifications::PDB_EVT_PE_TX_ERR) == (uint32_t)Notifications::PDB_EVT_PE_TX_ERR) { return PESinkHardReset; } /* Wait for a response */ - evt = waitForEvent(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET, PD_T_SENDER_RESPONSE); + evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_MSG_RX | (uint32_t)Notifications::PDB_EVT_PE_RESET, PD_T_SENDER_RESPONSE); /* If we got reset signaling, transition to default */ - if (evt & PDB_EVT_PE_RESET) { + if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) { return PESinkTransitionDefault; } /* If we didn't get a response before the timeout, send a hard reset */ if (evt == 0) { - return PESinkHardReset; + return PESinkSoftReset; } /* Get the response message */ @@ -265,7 +266,6 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_select_cap() { readMessage(); /* If the source accepted our request, wait for the new power */ if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_ACCEPT && PD_NUMOBJ_GET(&tempMessage) == 0) { - return PESinkTransitionSink; /* If the message was a Soft_Reset, do the soft reset procedure */ } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SOFT_RESET && PD_NUMOBJ_GET(&tempMessage) == 0) { @@ -280,7 +280,7 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_select_cap() { return PESinkReady; } } else { - return PESinkSendSoftReset; + return PESinkSoftReset; } } return PESinkHardReset; @@ -288,111 +288,97 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_select_cap() { PolicyEngine::policy_engine_state PolicyEngine::pe_sink_transition_sink() { /* Wait for the PS_RDY message */ - eventmask_t evt = waitForEvent(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET, PD_T_PS_TRANSITION); + EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_MSG_RX | (uint32_t)Notifications::PDB_EVT_PE_RESET, PD_T_PS_TRANSITION); /* If we got reset signaling, transition to default */ - if (evt & PDB_EVT_PE_RESET) { + if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) { return PESinkTransitionDefault; } - /* If no message was received, send a hard reset */ - if (evt == 0) { - return PESinkHardReset; - } /* If we received a message, read it */ - if (messageWaiting()) { + while (messageWaiting()) { readMessage(); /* If we got a PS_RDY, handle it */ if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_PS_RDY && PD_NUMOBJ_GET(&tempMessage) == 0) { /* We just finished negotiating an explicit contract */ _explicit_contract = true; - /* Set the output appropriately */ + /* Negotiation finished */ pdbs_dpm_transition_requested(); return PESinkReady; /* If there was a protocol error, send a hard reset */ - } else { - /* Turn off the power output before this hard reset to make sure we - * don't supply an incorrect voltage to the device we're powering. - */ - pdbs_dpm_transition_default(); - - return PESinkHardReset; } } - - return PESinkHardReset; + return PESinkSoftReset; } PolicyEngine::policy_engine_state PolicyEngine::pe_sink_ready() { - eventmask_t evt; - - /* Wait for an event */ - evt = waitForEvent(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET | PDB_EVT_PE_I_OVRTEMP); - + EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_ALL); + /* If SinkPPSPeriodicTimer ran out, send a new request */ + if (evt & (uint32_t)Notifications::PDB_EVT_PE_PPS_REQUEST) { + return PESinkSelectCap; + } /* If we got reset signaling, transition to default */ - if (evt & PDB_EVT_PE_RESET) { + if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) { return PESinkTransitionDefault; } /* If we overheated, send a hard reset */ - if (evt & PDB_EVT_PE_I_OVRTEMP) { + if (evt & (uint32_t)Notifications::PDB_EVT_PE_I_OVRTEMP) { return PESinkHardReset; } + /* If the DPM wants us to, send a Get_Source_Cap message */ + if (evt & (uint32_t)Notifications::PDB_EVT_PE_GET_SOURCE_CAP) { + return PESinkGetSourceCap; + } + /* If the DPM wants new power, let it figure out what power it wants + * exactly. This isn't exactly the transition from the spec (that would be + * SelectCap, not EvalCap), but this works better with the particular + * design of this firmware. */ + if (evt & (uint32_t)Notifications::PDB_EVT_PE_NEW_POWER) { + /* Tell the protocol layer we're starting an AMS */ + return PESinkEvalCap; + } /* If we received a message */ - if (evt & PDB_EVT_PE_MSG_RX) { + if (evt & (uint32_t)Notifications::PDB_EVT_PE_MSG_RX) { if (messageWaiting()) { readMessage(); /* Ignore vendor-defined messages */ if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_VENDOR_DEFINED && PD_NUMOBJ_GET(&tempMessage) > 0) { - return PESinkReady; /* Ignore Ping messages */ } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_PING && PD_NUMOBJ_GET(&tempMessage) == 0) { - return PESinkReady; /* DR_Swap messages are not supported */ } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_DR_SWAP && PD_NUMOBJ_GET(&tempMessage) == 0) { - return PESinkSendNotSupported; /* Get_Source_Cap messages are not supported */ } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_GET_SOURCE_CAP && PD_NUMOBJ_GET(&tempMessage) == 0) { - return PESinkSendNotSupported; /* PR_Swap messages are not supported */ } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_PR_SWAP && PD_NUMOBJ_GET(&tempMessage) == 0) { - return PESinkSendNotSupported; /* VCONN_Swap messages are not supported */ } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_VCONN_SWAP && PD_NUMOBJ_GET(&tempMessage) == 0) { - return PESinkSendNotSupported; /* Request messages are not supported */ } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_REQUEST && PD_NUMOBJ_GET(&tempMessage) > 0) { - return PESinkSendNotSupported; /* Sink_Capabilities messages are not supported */ } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SINK_CAPABILITIES && PD_NUMOBJ_GET(&tempMessage) > 0) { - return PESinkSendNotSupported; /* Handle GotoMin messages */ } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_GOTOMIN && PD_NUMOBJ_GET(&tempMessage) == 0) { - /* GiveBack is not supported */ return PESinkSendNotSupported; - /* Evaluate new Source_Capabilities */ } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SOURCE_CAPABILITIES && PD_NUMOBJ_GET(&tempMessage) > 0) { - /* Don't free the message: we need to keep the - * Source_Capabilities message so we can evaluate it. */ return PESinkEvalCap; /* Give sink capabilities when asked */ } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_GET_SINK_CAP && PD_NUMOBJ_GET(&tempMessage) == 0) { - return PESinkGiveSinkCap; /* If the message was a Soft_Reset, do the soft reset procedure */ } else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SOFT_RESET && PD_NUMOBJ_GET(&tempMessage) == 0) { - return PESinkSoftReset; /* PD 3.0 messges */ } else if ((hdr_template & PD_HDR_SPECREV) == PD_SPECREV_3_0) { @@ -411,9 +397,6 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_ready() { return PESinkSendSoftReset; } - } else { - /* if we get an unknown message code, silently ignore it*/ - return PESinkReady; } } } @@ -428,15 +411,14 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_get_source_cap() { get_source_cap->hdr = hdr_template | PD_MSGTYPE_GET_SOURCE_CAP | PD_NUMOBJ(0); /* Transmit the Get_Source_Cap */ ProtocolTransmit::pushMessage(get_source_cap); - ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_MSG_TX); - eventmask_t evt = waitForEvent(PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET); + EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_TX_DONE | (uint32_t)Notifications::PDB_EVT_PE_TX_ERR | (uint32_t)Notifications::PDB_EVT_PE_RESET); /* Free the sent message */ /* If we got reset signaling, transition to default */ - if (evt & PDB_EVT_PE_RESET) { + if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) { return PESinkTransitionDefault; } /* If the message transmission failed, send a hard reset */ - if ((evt & PDB_EVT_PE_TX_DONE) == 0) { + if ((evt & (uint32_t)Notifications::PDB_EVT_PE_TX_DONE) == 0) { return PESinkHardReset; } @@ -451,17 +433,16 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_give_sink_cap() { /* Transmit our capabilities */ ProtocolTransmit::pushMessage(snk_cap); - ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_MSG_TX); - eventmask_t evt = waitForEvent(PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET); + EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_TX_DONE | (uint32_t)Notifications::PDB_EVT_PE_TX_ERR | (uint32_t)Notifications::PDB_EVT_PE_RESET); /* Free the Sink_Capabilities message */ /* If we got reset signaling, transition to default */ - if (evt & PDB_EVT_PE_RESET) { + if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) { return PESinkTransitionDefault; } /* If the message transmission failed, send a hard reset */ - if ((evt & PDB_EVT_PE_TX_DONE) == 0) { + if ((evt & (uint32_t)Notifications::PDB_EVT_PE_TX_DONE) == 0) { return PESinkHardReset; } @@ -505,16 +486,15 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_soft_reset() { accept.hdr = hdr_template | PD_MSGTYPE_ACCEPT | PD_NUMOBJ(0); /* Transmit the Accept */ ProtocolTransmit::pushMessage(&accept); - ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_MSG_TX); - eventmask_t evt = waitForEvent(PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET); + EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_TX_DONE | (uint32_t)Notifications::PDB_EVT_PE_TX_ERR | (uint32_t)Notifications::PDB_EVT_PE_RESET); /* Free the sent message */ /* If we got reset signaling, transition to default */ - if (evt & PDB_EVT_PE_RESET) { + if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) { return PESinkTransitionDefault; } /* If the message transmission failed, send a hard reset */ - if ((evt & PDB_EVT_PE_TX_DONE) == 0) { + if ((evt & (uint32_t)Notifications::PDB_EVT_PE_TX_DONE) == 0) { return PESinkHardReset; } @@ -531,21 +511,20 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_send_soft_reset() { softrst->hdr = hdr_template | PD_MSGTYPE_SOFT_RESET | PD_NUMOBJ(0); /* Transmit the soft reset */ ProtocolTransmit::pushMessage(softrst); - ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_MSG_TX); - eventmask_t evt = waitForEvent(PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET); + EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_TX_DONE | (uint32_t)Notifications::PDB_EVT_PE_TX_ERR | (uint32_t)Notifications::PDB_EVT_PE_RESET); /* If we got reset signaling, transition to default */ - if (evt & PDB_EVT_PE_RESET) { + if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) { return PESinkTransitionDefault; } /* If the message transmission failed, send a hard reset */ - if ((evt & PDB_EVT_PE_TX_DONE) == 0) { + if ((evt & (uint32_t)Notifications::PDB_EVT_PE_TX_DONE) == 0) { return PESinkHardReset; } /* Wait for a response */ - evt = waitForEvent(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET, PD_T_SENDER_RESPONSE); + evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_MSG_RX | (uint32_t)Notifications::PDB_EVT_PE_RESET, PD_T_SENDER_RESPONSE); /* If we got reset signaling, transition to default */ - if (evt & PDB_EVT_PE_RESET) { + if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) { return PESinkTransitionDefault; } /* If we didn't get a response before the timeout, send a hard reset */ @@ -575,27 +554,25 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_send_soft_reset() { PolicyEngine::policy_engine_state PolicyEngine::pe_sink_send_not_supported() { /* Get a message object */ - union pd_msg *not_supported = &tempMessage; if ((hdr_template & PD_HDR_SPECREV) == PD_SPECREV_2_0) { /* Make a Reject message */ - not_supported->hdr = hdr_template | PD_MSGTYPE_REJECT | PD_NUMOBJ(0); + tempMessage.hdr = hdr_template | PD_MSGTYPE_REJECT | PD_NUMOBJ(0); } else if ((hdr_template & PD_HDR_SPECREV) == PD_SPECREV_3_0) { /* Make a Not_Supported message */ - not_supported->hdr = hdr_template | PD_MSGTYPE_NOT_SUPPORTED | PD_NUMOBJ(0); + tempMessage.hdr = hdr_template | PD_MSGTYPE_NOT_SUPPORTED | PD_NUMOBJ(0); } /* Transmit the message */ - ProtocolTransmit::pushMessage(not_supported); - ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_MSG_TX); - eventmask_t evt = waitForEvent(PDB_EVT_PE_TX_DONE | PDB_EVT_PE_TX_ERR | PDB_EVT_PE_RESET); + ProtocolTransmit::pushMessage(&tempMessage); + EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_TX_DONE | (uint32_t)Notifications::PDB_EVT_PE_TX_ERR | (uint32_t)Notifications::PDB_EVT_PE_RESET); /* If we got reset signaling, transition to default */ - if (evt & PDB_EVT_PE_RESET) { + if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) { return PESinkTransitionDefault; } /* If the message transmission failed, send a soft reset */ - if ((evt & PDB_EVT_PE_TX_DONE) == 0) { + if ((evt & (uint32_t)Notifications::PDB_EVT_PE_TX_DONE) == 0) { return PESinkSendSoftReset; } @@ -605,9 +582,9 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_send_not_supported() { PolicyEngine::policy_engine_state PolicyEngine::pe_sink_chunk_received() { /* Wait for tChunkingNotSupported */ - eventmask_t evt = waitForEvent(PDB_EVT_PE_RESET, PD_T_CHUNKING_NOT_SUPPORTED); + EventBits_t evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PE_RESET, PD_T_CHUNKING_NOT_SUPPORTED); /* If we got reset signaling, transition to default */ - if (evt & PDB_EVT_PE_RESET) { + if (evt & (uint32_t)Notifications::PDB_EVT_PE_RESET) { return PESinkTransitionDefault; } @@ -628,6 +605,23 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_source_unresponsive() { return PESinkSourceUnresponsive; } -uint32_t PolicyEngine::waitForEvent(uint32_t mask, TickType_t ticksToWait) { return xEventGroupWaitBits(xEventGroupHandle, mask, mask, pdFALSE, ticksToWait); } +EventBits_t PolicyEngine::waitForEvent(uint32_t mask, TickType_t ticksToWait) { return xEventGroupWaitBits(xEventGroupHandle, mask, mask, pdFALSE, ticksToWait); } bool PolicyEngine::isPD3_0() { return (hdr_template & PD_HDR_SPECREV) == PD_SPECREV_3_0; } + +void PolicyEngine::handleMessage(union pd_msg *msg) { + xQueueSend(messagesWaiting, msg, 100); + notify(PolicyEngine::Notifications::PDB_EVT_PE_MSG_RX); +} + +void PolicyEngine::PPSTimerCallback() { + if (PPSTimerEnabled && state == policy_engine_state::PESinkReady) { + // I believe even once per second is totally fine, but leaning on faster since everything seems cool with faster + // Have seen everything from 10ms to 1 second :D + if ((xTaskGetTickCount() - PPSTimeLastEvent) > (TICKS_SECOND)) { + // Send a new PPS message + PolicyEngine::notify(Notifications::PDB_EVT_PE_PPS_REQUEST); + PPSTimeLastEvent = xTaskGetTickCount(); + } + } +} diff --git a/source/Core/Drivers/FUSB302/policy_engine.h b/source/Core/Drivers/FUSB302/policy_engine.h index c97ce063..489b7a50 100644 --- a/source/Core/Drivers/FUSB302/policy_engine.h +++ b/source/Core/Drivers/FUSB302/policy_engine.h @@ -25,22 +25,12 @@ * */ -#define PDB_EVT_PE_RESET EVENT_MASK(0) -#define PDB_EVT_PE_MSG_RX EVENT_MASK(1) -#define PDB_EVT_PE_TX_DONE EVENT_MASK(2) -#define PDB_EVT_PE_TX_ERR EVENT_MASK(3) -#define PDB_EVT_PE_HARD_SENT EVENT_MASK(4) -#define PDB_EVT_PE_I_OVRTEMP EVENT_MASK(5) -#define PDB_EVT_PE_MSG_RX_PEND EVENT_MASK(7) /* Never SEND THIS DIRECTLY*/ - class PolicyEngine { public: // Sets up internal state and registers the thread static void init(); // Push an incoming message to the Policy Engine static void handleMessage(union pd_msg *msg); - // Send a notification - static void notify(uint32_t notification); // Returns true if headers indicate PD3.0 compliant static bool isPD3_0(); static bool setupCompleteOrTimedOut() { @@ -53,7 +43,30 @@ public: return false; } // Has pd negotiation completed - static bool pdHasNegotiated() { return pdNegotiationComplete; } + static bool pdHasNegotiated() { + if (state == policy_engine_state::PESinkSourceUnresponsive) + return false; + return true; + } + // Call this periodically, at least once every second + static void PPSTimerCallback(); + + enum class Notifications { + PDB_EVT_PE_RESET = EVENT_MASK(0), + PDB_EVT_PE_MSG_RX = EVENT_MASK(1), + PDB_EVT_PE_TX_DONE = EVENT_MASK(2), + PDB_EVT_PE_TX_ERR = EVENT_MASK(3), + PDB_EVT_PE_HARD_SENT = EVENT_MASK(4), + PDB_EVT_PE_I_OVRTEMP = EVENT_MASK(5), + PDB_EVT_PE_PPS_REQUEST = EVENT_MASK(6), + PDB_EVT_PE_GET_SOURCE_CAP = EVENT_MASK(7), + PDB_EVT_PE_NEW_POWER = EVENT_MASK(8), + PDB_EVT_PE_ALL = (EVENT_MASK(9) - 1), + }; + // Send a notification + static void notify(Notifications notification); + // Debugging allows looking at state + static uint32_t getState() { return (uint32_t)state; } private: static bool pdNegotiationComplete; @@ -72,17 +85,16 @@ private: static int8_t _old_tcc_match; /* The index of the first PPS APDO */ static uint8_t _pps_index; - /* The index of the just-requested PPS APDO */ - static uint8_t _last_pps; - static void pe_task(const void *arg); + + static void pe_task(const void *arg); enum policy_engine_state { PESinkStartup, PESinkDiscovery, PESinkWaitCap, PESinkEvalCap, - PESinkSelectCap, - PESinkTransitionSink, - PESinkReady, + PESinkSelectCap, // 4 + PESinkTransitionSink, // 5 + PESinkReady, // 6 PESinkGetSourceCap, PESinkGiveSinkCap, PESinkHardReset, @@ -113,7 +125,7 @@ private: static enum policy_engine_state pe_sink_source_unresponsive(); static EventGroupHandle_t xEventGroupHandle; static StaticEventGroup_t xCreatedEventGroup; - static uint32_t waitForEvent(uint32_t mask, TickType_t ticksToWait = portMAX_DELAY); + static EventBits_t waitForEvent(uint32_t mask, TickType_t ticksToWait = portMAX_DELAY); // Task resources static osThreadId TaskHandle; static const size_t TaskStackSize = 2048 / 4; @@ -130,7 +142,9 @@ private: static QueueHandle_t messagesWaiting; static bool messageWaiting(); // Read a pending message into the temp message - static bool readMessage(); + static bool readMessage(); + static bool PPSTimerEnabled; + static TickType_t PPSTimeLastEvent; // These callbacks are called to implement the logic for the iron to select the desired voltage diff --git a/source/Core/Drivers/FUSB302/policy_engine_user.cpp b/source/Core/Drivers/FUSB302/policy_engine_user.cpp index 0241436b..89f72c3e 100644 --- a/source/Core/Drivers/FUSB302/policy_engine_user.cpp +++ b/source/Core/Drivers/FUSB302/policy_engine_user.cpp @@ -5,10 +5,12 @@ * Author: Ralim */ #include "BSP_PD.h" +#include "configuration.h" #include "pd.h" #include "policy_engine.h" + /* The current draw when the output is disabled */ -#define DPM_MIN_CURRENT PD_MA2PDI(50) +#define DPM_MIN_CURRENT PD_MA2PDI(100) /* * Find the index of the first PDO from capabilities in the voltage range, * using the desired order. @@ -54,52 +56,88 @@ bool PolicyEngine::pdbs_dpm_evaluate_capability(const union pd_msg *capabilities /* Make sure we have configuration */ /* Look at the PDOs to see if one matches our desires */ // Look against USB_PD_Desired_Levels to select in order of preference - for (uint8_t desiredLevel = 0; desiredLevel < USB_PD_Desired_Levels_Len; desiredLevel++) { - for (uint8_t i = 0; i < numobj; i++) { - /* If we have a fixed PDO, its V equals our desired V, and its I is - * at least our desired I */ - if ((capabilities->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED) { - // This is a fixed PDO entry - int voltage = PD_PDV2MV(PD_PDO_SRC_FIXED_VOLTAGE_GET(capabilities->obj[i])); - int current = PD_PDO_SRC_FIXED_CURRENT_GET(capabilities->obj[i]); - uint16_t desiredVoltage = USB_PD_Desired_Levels[(desiredLevel * 2) + 0]; - uint16_t desiredminCurrent = USB_PD_Desired_Levels[(desiredLevel * 2) + 1]; - // As pd stores current in 10mA increments, divide by 10 - desiredminCurrent /= 10; - if (voltage == desiredVoltage) { - if (current >= desiredminCurrent) { - /* We got what we wanted, so build a request for that */ - request->hdr = hdr_template | PD_MSGTYPE_REQUEST | PD_NUMOBJ(1); + uint8_t bestIndex = 0xFF; + int bestIndexVoltage = 0; + int bestIndexCurrent = 0; + bool bestIsPPS = false; + for (uint8_t i = 0; i < numobj; i++) { + /* If we have a fixed PDO, its V equals our desired V, and its I is + * at least our desired I */ + if ((capabilities->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED) { + // This is a fixed PDO entry + // Evaluate if it can produve sufficient current based on the tipResistance (ohms*10) + // V=I*R -> V/I => minimum resistance, if our tip resistance is >= this then we can use this supply - /* GiveBack disabled */ - request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(current) | PD_RDO_FV_CURRENT_SET(current) | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(i + 1); - // We support usb comms (ish) - request->obj[0] |= PD_RDO_USB_COMMS; - - /* Update requested voltage */ - _requested_voltage = voltage; - - return true; + int voltage_mv = PD_PDV2MV(PD_PDO_SRC_FIXED_VOLTAGE_GET(capabilities->obj[i])); // voltage in mV units + int current_a_x100 = PD_PDO_SRC_FIXED_CURRENT_GET(capabilities->obj[i]); // current in 10mA units + int min_resistance_ohmsx10 = voltage_mv / current_a_x100; + if (voltage_mv <= (USB_PD_VMAX * 1000)) { + if (min_resistance_ohmsx10 <= tipResistance) { + // This is a valid power source we can select as + if (voltage_mv > bestIndexVoltage || bestIndex == 0xFF) { + // Higher voltage and valid, select this instead + bestIndex = i; + bestIndexVoltage = voltage_mv; + bestIndexCurrent = current_a_x100; + bestIsPPS = false; } } } + } else + + if ((capabilities->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_AUGMENTED && (capabilities->obj[i] & PD_APDO_TYPE) == PD_APDO_TYPE_PPS) { + // If this is a PPS slot, calculate the max voltage in the PPS range that can we be used and maintain + uint16_t max_voltage = PD_PAV2MV(PD_APDO_PPS_MAX_VOLTAGE_GET(capabilities->obj[i])); + // uint16_t min_voltage = PD_PAV2MV(PD_APDO_PPS_MIN_VOLTAGE_GET(capabilities->obj[i])); + uint16_t max_current = PD_PAI2CA(PD_APDO_PPS_CURRENT_GET(capabilities->obj[i])); // max current in 10mA units + // Using the current and tip resistance, calculate the ideal max voltage + // if this is range, then we will work with this voltage + // if this is not in range; then max_voltage can be safely selected + int ideal_voltage_mv = (tipResistance * max_current); + if (ideal_voltage_mv > max_voltage) { + ideal_voltage_mv = max_voltage; // constrain + } + if (ideal_voltage_mv > (USB_PD_VMAX * 1000)) { + ideal_voltage_mv = (USB_PD_VMAX * 1000); // constrain to model max + } + if (ideal_voltage_mv > bestIndexVoltage || bestIndex == 0xFF) { + bestIndex = i; + bestIndexVoltage = ideal_voltage_mv; + bestIndexCurrent = max_current; + bestIsPPS = true; + } } } + if (bestIndex != 0xFF) { + /* We got what we wanted, so build a request for that */ + request->hdr = hdr_template | PD_MSGTYPE_REQUEST | PD_NUMOBJ(1); + if (bestIsPPS) { + request->obj[0] = PD_RDO_PROG_CURRENT_SET(PD_CA2PAI(bestIndexCurrent)) | PD_RDO_PROG_VOLTAGE_SET(PD_MV2PRV(bestIndexVoltage)) | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(bestIndex + 1); + } else { + request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(bestIndexCurrent) | PD_RDO_FV_CURRENT_SET(bestIndexCurrent) | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(bestIndex + 1); + } + // We dont do usb + // request->obj[0] |= PD_RDO_USB_COMMS; - /* Nothing matched (or no configuration), so get 5 V at low current */ - request->hdr = hdr_template | PD_MSGTYPE_REQUEST | PD_NUMOBJ(1); - request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(DPM_MIN_CURRENT) | PD_RDO_FV_CURRENT_SET(DPM_MIN_CURRENT) | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(1); - /* If the output is enabled and we got here, it must be a capability - * mismatch. */ - if (pdNegotiationComplete) { - request->obj[0] |= PD_RDO_CAP_MISMATCH; + /* Update requested voltage */ + _requested_voltage = bestIndexVoltage; + + } else { + /* Nothing matched (or no configuration), so get 5 V at low current */ + request->hdr = hdr_template | PD_MSGTYPE_REQUEST | PD_NUMOBJ(1); + request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(DPM_MIN_CURRENT) | PD_RDO_FV_CURRENT_SET(DPM_MIN_CURRENT) | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(1); + /* If the output is enabled and we got here, it must be a capability mismatch. */ + if (pdNegotiationComplete) { + request->obj[0] |= PD_RDO_CAP_MISMATCH; + } + // We dont do usb + // request->obj[0] |= PD_RDO_USB_COMMS; + + /* Update requested voltage */ + _requested_voltage = 5000; } - request->obj[0] |= PD_RDO_USB_COMMS; - - /* Update requested voltage */ - _requested_voltage = 5000; - - return false; + // Even if we didnt match, we return true as we would still like to handshake on 5V at the minimum + return true; } void PolicyEngine::pdbs_dpm_get_sink_capability(union pd_msg *cap) { @@ -112,8 +150,12 @@ void PolicyEngine::pdbs_dpm_get_sink_capability(union pd_msg *cap) { cap->obj[numobj++] = PD_PDO_TYPE_FIXED | PD_PDO_SNK_FIXED_VOLTAGE_SET(PD_MV2PDV(5000)) | PD_PDO_SNK_FIXED_CURRENT_SET(DPM_MIN_CURRENT); /* Get the current we want */ - uint16_t current = USB_PD_Desired_Levels[1] / 10; // In centi-amps - uint16_t voltage = USB_PD_Desired_Levels[0]; // in mv + uint16_t voltage = USB_PD_VMAX * 1000; // in mv + if (_requested_voltage != 5000) { + voltage = _requested_voltage; + } + uint16_t current = (voltage) / tipResistance; // In centi-amps + /* Add a PDO for the desired power. */ cap->obj[numobj++] = PD_PDO_TYPE_FIXED | PD_PDO_SNK_FIXED_VOLTAGE_SET(PD_MV2PDV(voltage)) | PD_PDO_SNK_FIXED_CURRENT_SET(current); @@ -143,6 +185,11 @@ void PolicyEngine::pdbs_dpm_get_sink_capability(union pd_msg *cap) { cap->obj[2] ^= cap->obj[1]; cap->obj[1] ^= cap->obj[2]; } + /* If we're using PD 3.0, add a PPS APDO for our desired voltage */ + if ((hdr_template & PD_HDR_SPECREV) >= PD_SPECREV_3_0) { + cap->obj[numobj++] + = PD_PDO_TYPE_AUGMENTED | PD_APDO_TYPE_PPS | PD_APDO_PPS_MAX_VOLTAGE_SET(PD_MV2PAV(voltage)) | PD_APDO_PPS_MIN_VOLTAGE_SET(PD_MV2PAV(voltage)) | PD_APDO_PPS_CURRENT_SET(PD_CA2PAI(current)); + } } /* Set the unconstrained power flag. */ @@ -167,7 +214,6 @@ bool PolicyEngine::pdbs_dpm_evaluate_typec_current(enum fusb_typec_current tcc) } void PolicyEngine::pdbs_dpm_transition_default() { - /* Cast the dpm_data to the right type */ /* Pretend we requested 5 V */ current_voltage_mv = 5000; @@ -175,12 +221,7 @@ void PolicyEngine::pdbs_dpm_transition_default() { pdNegotiationComplete = false; } -void PolicyEngine::pdbs_dpm_transition_requested() { - /* Cast the dpm_data to the right type */ - pdNegotiationComplete = true; -} - -void PolicyEngine::handleMessage(union pd_msg *msg) { xQueueSend(messagesWaiting, msg, 100); } +void PolicyEngine::pdbs_dpm_transition_requested() { pdNegotiationComplete = true; } bool PolicyEngine::messageWaiting() { return uxQueueMessagesWaiting(messagesWaiting) > 0; } diff --git a/source/Core/Drivers/FUSB302/protocol_rx.cpp b/source/Core/Drivers/FUSB302/protocol_rx.cpp deleted file mode 100644 index 2c87f325..00000000 --- a/source/Core/Drivers/FUSB302/protocol_rx.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/* - * PD Buddy Firmware Library - USB Power Delivery for everyone - * Copyright 2017-2018 Clayton G. Hobbs - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "protocol_rx.h" - -#include "fusb302b.h" -#include "policy_engine.h" -#include "protocol_tx.h" -#include "string.h" -#include -#include -osThreadId ProtocolReceive::TaskHandle = NULL; -EventGroupHandle_t ProtocolReceive::xEventGroupHandle = NULL; -StaticEventGroup_t ProtocolReceive::xCreatedEventGroup; -uint32_t ProtocolReceive::TaskBuffer[ProtocolReceive::TaskStackSize]; -osStaticThreadDef_t ProtocolReceive::TaskControlBlock; -union pd_msg ProtocolReceive::tempMessage; -uint8_t ProtocolReceive::_rx_messageid; -uint8_t ProtocolReceive::_tx_messageidcounter; -/* - * PRL_Rx_Wait_for_PHY_Message state - */ -ProtocolReceive::protocol_rx_state ProtocolReceive::protocol_rx_wait_phy() { - /* Wait for an event */ - _rx_messageid = 0; - eventmask_t evt = waitForEvent(PDB_EVT_PRLRX_RESET | PDB_EVT_PRLRX_I_GCRCSENT | PDB_EVT_PRLRX_I_RXPEND); - - /* If we got a reset event, reset */ - if (evt & PDB_EVT_PRLRX_RESET) { - waitForEvent(PDB_EVT_PRLRX_RESET, 0); - return PRLRxWaitPHY; - } - /* If we got an I_GCRCSENT event, read the message and decide what to do */ - if (evt & PDB_EVT_PRLRX_I_GCRCSENT) { - /* Get a buffer to read the message into. Guaranteed to not fail - * because we have a big enough pool and are careful. */ - union pd_msg *_rx_message = &tempMessage; - memset(&tempMessage, 0, sizeof(tempMessage)); - /* Read the message */ - fusb_read_message(_rx_message); - /* If it's a Soft_Reset, go to the soft reset state */ - if (PD_MSGTYPE_GET(_rx_message) == PD_MSGTYPE_SOFT_RESET && PD_NUMOBJ_GET(_rx_message) == 0) { - return PRLRxReset; - } else { - /* Otherwise, check the message ID */ - return PRLRxCheckMessageID; - } - } else if (evt & PDB_EVT_PRLRX_I_RXPEND) { - // There is an RX message pending that is not a Good CRC - union pd_msg *_rx_message = &tempMessage; - /* Read the message */ - fusb_read_message(_rx_message); - return PRLRxWaitPHY; - } - - return PRLRxWaitPHY; -} - -/* - * PRL_Rx_Layer_Reset_for_Receive state - */ -ProtocolReceive::protocol_rx_state ProtocolReceive::protocol_rx_reset() { - /* Reset MessageIDCounter */ - _tx_messageidcounter = 0; - - /* Clear stored MessageID */ - _rx_messageid = -1; - - /* TX transitions to its reset state */ - ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_RESET); - taskYIELD(); - - /* If we got a RESET signal, reset the machine */ - if (waitForEvent(PDB_EVT_PRLRX_RESET, 0) != 0) { - return PRLRxWaitPHY; - } - - /* Go to the Check_MessageID state */ - return PRLRxCheckMessageID; -} -volatile uint32_t rxCounter = 0; -/* - * PRL_Rx_Check_MessageID state - */ -ProtocolReceive::protocol_rx_state ProtocolReceive::protocol_rx_check_messageid() { - /* If we got a RESET signal, reset the machine */ - // if (waitForEvent(PDB_EVT_PRLRX_RESET, 0) == PDB_EVT_PRLRX_RESET) { - // return PRLRxWaitPHY; - // } - /* If the message has the stored ID, we've seen this message before. Free - * it and don't pass it to the policy engine. */ - - /* Otherwise, there's either no stored ID or this message has an ID we - * haven't just seen. Transition to the Store_MessageID state. */ - // if (PD_MESSAGEID_GET(&tempMessage) == _rx_messageid) { - // return PRLRxWaitPHY; - // } else - { - rxCounter++; - return PRLRxStoreMessageID; - } -} - -/* - * PRL_Rx_Store_MessageID state - */ -ProtocolReceive::protocol_rx_state ProtocolReceive::protocol_rx_store_messageid() { - /* Tell ProtocolTX to discard the message being transmitted */ - - ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_DISCARD); - - /* Update the stored MessageID */ - _rx_messageid = PD_MESSAGEID_GET(&tempMessage); - - /* Pass the message to the policy engine. */ - - PolicyEngine::handleMessage(&tempMessage); - PolicyEngine::notify(PDB_EVT_PE_MSG_RX); - taskYIELD(); - /* Don't check if we got a RESET because we'd do nothing different. */ - - return PRLRxWaitPHY; -} - -void ProtocolReceive::init() { - osThreadStaticDef(protRX, thread, PDB_PRIO_PRL, 0, TaskStackSize, TaskBuffer, &TaskControlBlock); - xEventGroupHandle = xEventGroupCreateStatic(&xCreatedEventGroup); - TaskHandle = osThreadCreate(osThread(protRX), NULL); -} - -void ProtocolReceive::thread(const void *args) { - (void)args; - ProtocolReceive::protocol_rx_state state = PRLRxWaitPHY; - - while (true) { - switch (state) { - case PRLRxWaitPHY: - state = protocol_rx_wait_phy(); - break; - case PRLRxReset: - state = protocol_rx_reset(); - break; - case PRLRxCheckMessageID: - state = protocol_rx_check_messageid(); - break; - case PRLRxStoreMessageID: - state = protocol_rx_store_messageid(); - break; - default: - /* This is an error. It really shouldn't happen. We might - * want to handle it anyway, though. */ - state = PRLRxWaitPHY; - break; - } - } -} - -void ProtocolReceive::notify(uint32_t notification) { - if (xEventGroupHandle != NULL) { - xEventGroupSetBits(xEventGroupHandle, notification); - } -} - -uint32_t ProtocolReceive::waitForEvent(uint32_t mask, TickType_t ticksToWait) { - if (xEventGroupHandle != NULL) { - return xEventGroupWaitBits(xEventGroupHandle, mask, mask, pdFALSE, ticksToWait); - } - return 0; -} diff --git a/source/Core/Drivers/FUSB302/protocol_rx.h b/source/Core/Drivers/FUSB302/protocol_rx.h deleted file mode 100644 index 2521c30e..00000000 --- a/source/Core/Drivers/FUSB302/protocol_rx.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * PD Buddy Firmware Library - USB Power Delivery for everyone - * Copyright 2017-2018 Clayton G. Hobbs - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef PDB_PROTOCOL_RX_H -#define PDB_PROTOCOL_RX_H - -#include - -#include - -/* Events for the Protocol RX thread */ -#define PDB_EVT_PRLRX_RESET EVENT_MASK(0) -#define PDB_EVT_PRLRX_I_GCRCSENT EVENT_MASK(1) -#define PDB_EVT_PRLRX_I_RXPEND EVENT_MASK(2) - -class ProtocolReceive { -public: - static void init(); - static void notify(uint32_t notification); - -private: - static void thread(const void *args); - - static EventGroupHandle_t xEventGroupHandle; - static StaticEventGroup_t xCreatedEventGroup; - static osThreadId TaskHandle; - static const size_t TaskStackSize = 1024 / 4; - static uint32_t TaskBuffer[TaskStackSize]; - static osStaticThreadDef_t TaskControlBlock; - /* - * Protocol RX machine states - * - * There is no Send_GoodCRC state because the PHY sends the GoodCRC for us. - * All transitions that would go to that state instead go to Check_MessageID. - */ - enum protocol_rx_state { PRLRxWaitPHY, PRLRxReset, PRLRxCheckMessageID, PRLRxStoreMessageID }; - static protocol_rx_state protocol_rx_store_messageid(); - static protocol_rx_state protocol_rx_check_messageid(); - static protocol_rx_state protocol_rx_reset(); - static protocol_rx_state protocol_rx_wait_phy(); - static union pd_msg tempMessage; - static uint8_t _rx_messageid; - static uint8_t _tx_messageidcounter; - static uint32_t waitForEvent(uint32_t mask, TickType_t ticksToWait = portMAX_DELAY); -}; - -#endif /* PDB_PROTOCOL_RX_H */ diff --git a/source/Core/Drivers/FUSB302/protocol_tx.cpp b/source/Core/Drivers/FUSB302/protocol_tx.cpp index fadc68af..ca9410b5 100644 --- a/source/Core/Drivers/FUSB302/protocol_tx.cpp +++ b/source/Core/Drivers/FUSB302/protocol_tx.cpp @@ -16,10 +16,10 @@ */ #include "protocol_tx.h" +#include "Defines.h" #include "fusb302b.h" #include "fusbpd.h" #include "policy_engine.h" -#include "protocol_rx.h" #include osThreadId ProtocolTransmit::TaskHandle = NULL; @@ -44,7 +44,7 @@ ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_phy_reset() { * we failed to send it */ if (messagePending()) { /* Tell the policy engine that we failed */ - PolicyEngine::notify(PDB_EVT_PE_TX_ERR); + PolicyEngine::notify(PolicyEngine::Notifications::PDB_EVT_PE_TX_ERR); /* Finish failing to send the message */ while (messagePending()) { getMessage(); // Discard @@ -88,10 +88,6 @@ ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_reset() { /* Clear MessageIDCounter */ _tx_messageidcounter = 0; - /* Tell the Protocol RX thread to reset */ - ProtocolReceive::notify(PDB_EVT_PRLRX_RESET); - taskYIELD(); - return PRLTxConstructMessage; } @@ -104,17 +100,12 @@ ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_construct_mess temp_msg.hdr |= (_tx_messageidcounter % 8) << PD_HDR_MESSAGEID_SHIFT; /* PD 3.0 collision avoidance */ - // if (PolicyEngine::isPD3_0()) { - // /* If we're starting an AMS, wait for permission to transmit */ - // evt = waitForEvent((uint32_t) Notifications::PDB_EVT_PRLTX_START_AMS, - // 0); - // if ((uint32_t) evt - // & (uint32_t) Notifications::PDB_EVT_PRLTX_START_AMS) { - // while (fusb_get_typec_current() != fusb_sink_tx_ok) { - // osDelay(1); - // } - // } - // } + if (PolicyEngine::isPD3_0()) { + /* If we're starting an AMS, wait for permission to transmit */ + while (fusb_get_typec_current() != fusb_sink_tx_ok) { + vTaskDelay(TICKS_10MS); + } + } messageSending = true; /* Send the message to the PHY */ fusb_send_message(&temp_msg); @@ -173,7 +164,7 @@ ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_transmission_e _tx_messageidcounter = (_tx_messageidcounter + 1) % 8; /* Tell the policy engine that we failed */ - PolicyEngine::notify(PDB_EVT_PE_TX_ERR); + PolicyEngine::notify(PolicyEngine::Notifications::PDB_EVT_PE_TX_ERR); return PRLTxWaitMessage; } @@ -184,7 +175,7 @@ ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_message_sent() _tx_messageidcounter = (_tx_messageidcounter + 1) % 8; /* Tell the policy engine that we succeeded */ - PolicyEngine::notify(PDB_EVT_PE_TX_DONE); + PolicyEngine::notify(PolicyEngine::Notifications::PDB_EVT_PE_TX_DONE); return PRLTxWaitMessage; } @@ -257,7 +248,9 @@ void ProtocolTransmit::init() { void ProtocolTransmit::pushMessage(union pd_msg *msg) { if (messagesWaiting) { - xQueueSend(messagesWaiting, msg, 100); + if (xQueueSend(messagesWaiting, msg, 100) == pdTRUE) { + notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_MSG_TX); + } } } diff --git a/source/Core/Drivers/FUSB302/protocol_tx.h b/source/Core/Drivers/FUSB302/protocol_tx.h index 9c9b3414..0231f455 100644 --- a/source/Core/Drivers/FUSB302/protocol_tx.h +++ b/source/Core/Drivers/FUSB302/protocol_tx.h @@ -19,7 +19,7 @@ #define PDB_PROTOCOL_TX_H #include "policy_engine.h" -#include "protocol_rx.h" + #include #include @@ -38,7 +38,6 @@ public: PDB_EVT_PRLTX_I_RETRYFAIL = EVENT_MASK(2), // PDB_EVT_PRLTX_DISCARD = EVENT_MASK(3), // PDB_EVT_PRLTX_MSG_TX = EVENT_MASK(4), // - PDB_EVT_PRLTX_START_AMS = EVENT_MASK(5), // }; static void notify(Notifications notification); diff --git a/source/Core/Drivers/I2CBB.cpp b/source/Core/Drivers/I2CBB.cpp index 07474bfd..b55435d7 100644 --- a/source/Core/Drivers/I2CBB.cpp +++ b/source/Core/Drivers/I2CBB.cpp @@ -10,8 +10,6 @@ #include SemaphoreHandle_t I2CBB::I2CSemaphore = NULL; StaticSemaphore_t I2CBB::xSemaphoreBuffer; -SemaphoreHandle_t I2CBB::I2CSemaphore2 = NULL; -StaticSemaphore_t I2CBB::xSemaphoreBuffer2; void I2CBB::init() { // Set GPIO's to output open drain GPIO_InitTypeDef GPIO_InitStruct; @@ -28,10 +26,8 @@ void I2CBB::init() { HAL_GPIO_Init(SCL2_GPIO_Port, &GPIO_InitStruct); SOFT_SDA_HIGH(); SOFT_SCL_HIGH(); - I2CSemaphore = xSemaphoreCreateMutexStatic(&xSemaphoreBuffer); - I2CSemaphore2 = xSemaphoreCreateMutexStatic(&xSemaphoreBuffer2); + I2CSemaphore = xSemaphoreCreateMutexStatic(&xSemaphoreBuffer); unlock(); - unlock2(); } bool I2CBB::probe(uint8_t address) { @@ -291,14 +287,4 @@ void I2CBB::write_bit(uint8_t val) { SOFT_SCL_LOW(); } -void I2CBB::unlock2() { xSemaphoreGive(I2CSemaphore2); } - -bool I2CBB::lock2() { - if (I2CSemaphore2 == NULL) { - asm("bkpt"); - } - bool a = xSemaphoreTake(I2CSemaphore2, (TickType_t)500) == pdTRUE; - - return a; -} #endif diff --git a/source/Core/Drivers/I2CBB.hpp b/source/Core/Drivers/I2CBB.hpp index bd25b8df..7b580b07 100644 --- a/source/Core/Drivers/I2CBB.hpp +++ b/source/Core/Drivers/I2CBB.hpp @@ -28,14 +28,10 @@ public: static void Transmit(uint16_t DevAddress, uint8_t *pData, uint16_t Size); static void Receive(uint16_t DevAddress, uint8_t *pData, uint16_t Size); static void TransmitReceive(uint16_t DevAddress, uint8_t *pData_tx, uint16_t Size_tx, uint8_t *pData_rx, uint16_t Size_rx); - static void unlock2(); - static bool lock2(); private: static SemaphoreHandle_t I2CSemaphore; static StaticSemaphore_t xSemaphoreBuffer; - static SemaphoreHandle_t I2CSemaphore2; - static StaticSemaphore_t xSemaphoreBuffer2; static void unlock(); static bool lock(); static void start(); diff --git a/source/Core/Drivers/OLED.cpp b/source/Core/Drivers/OLED.cpp index ac6ca524..f1e057bc 100644 --- a/source/Core/Drivers/OLED.cpp +++ b/source/Core/Drivers/OLED.cpp @@ -5,9 +5,9 @@ * Author: Ben V. Brown */ -#include "../../configuration.h" #include "Translation.h" #include "cmsis_os.h" +#include "configuration.h" #include #include #include diff --git a/source/Core/Drivers/TipThermoModel.cpp b/source/Core/Drivers/TipThermoModel.cpp index 29bf1e7a..edf97fbc 100644 --- a/source/Core/Drivers/TipThermoModel.cpp +++ b/source/Core/Drivers/TipThermoModel.cpp @@ -6,9 +6,9 @@ */ #include "TipThermoModel.h" -#include "../../configuration.h" #include "BSP.h" #include "Settings.h" +#include "configuration.h" #include "main.hpp" #include "power.hpp" /* diff --git a/source/configuration.h b/source/Core/Inc/configuration.h similarity index 53% rename from source/configuration.h rename to source/Core/Inc/configuration.h index 43d76ce1..6de93bcb 100644 --- a/source/configuration.h +++ b/source/Core/Inc/configuration.h @@ -68,18 +68,18 @@ #define TEMP_CHANGE_LONG_STEP_MAX 90 // Temp change long step MAX value /* Power pulse for keeping power banks awake*/ -#define POWER_PULSE_INCREMENT 1 -#define POWER_PULSE_MAX 100 // x10 max watts -#define POWER_PULSE_WAIT_MAX 9 // 9*2.5s = 22.5 seconds -#define POWER_PULSE_DURATION_MAX 9 // 9*250ms = 2.25 seconds +#define POWER_PULSE_INCREMENT 1 +#define POWER_PULSE_MAX 100 // x10 max watts +#define POWER_PULSE_WAIT_MAX 9 // 9*2.5s = 22.5 seconds +#define POWER_PULSE_DURATION_MAX 9 // 9*250ms = 2.25 seconds #ifdef MODEL_TS100 #define POWER_PULSE_DEFAULT 0 #else #define POWER_PULSE_DEFAULT 5 #endif -#define POWER_PULSE_WAIT_DEFAULT 4; // Default rate of the power pulse: 4*2500 = 10000 ms = 10 s -#define POWER_PULSE_DURATION_DEFAULT 1; // Default duration of the power pulse: 1*250 = 250 ms +#define POWER_PULSE_WAIT_DEFAULT 4; // Default rate of the power pulse: 4*2500 = 10000 ms = 10 s +#define POWER_PULSE_DURATION_DEFAULT 1; // Default duration of the power pulse: 1*250 = 250 ms /** * OLED Orientation Sensitivity on Automatic mode! @@ -94,12 +94,12 @@ #define DETAILED_SOLDERING 0 // 0: Disable 1: Enable - Default 0 #define DETAILED_IDLE 0 // 0: Disable 1: Enable - Default 0 -#define CUT_OUT_SETTING 0 // default to no cut-off voltage -#define RECOM_VOL_CELL 33 // Minimum voltage per cell (Recommended 3.3V (33)) -#define TEMPERATURE_INF 0 // default to 0 -#define DESCRIPTION_SCROLL_SPEED 0 // 0: Slow 1: Fast - default to slow -#define ANIMATION_LOOP 1 // 0: off 1: on -#define ANIMATION_SPEED settingOffSpeed_t::MEDIUM +#define CUT_OUT_SETTING 0 // default to no cut-off voltage +#define RECOM_VOL_CELL 33 // Minimum voltage per cell (Recommended 3.3V (33)) +#define TEMPERATURE_INF 0 // default to 0 +#define DESCRIPTION_SCROLL_SPEED 0 // 0: Slow 1: Fast - default to slow +#define ANIMATION_LOOP 1 // 0: off 1: on +#define ANIMATION_SPEED settingOffSpeed_t::MEDIUM #define OP_AMP_Rf_TS100 750 * 1000 // 750 Kilo-ohms -> From schematic, R1 #define OP_AMP_Rin_TS100 2370 // 2.37 Kilo-ohms -> From schematic, R2 @@ -116,47 +116,51 @@ // vdiv = (32768*4)/(vin_max*10) #ifdef MODEL_TS100 -#define VOLTAGE_DIV 467 // 467 - Default divider from schematic -#define CALIBRATION_OFFSET 900 // 900 - Default adc offset in uV -#define PID_POWER_LIMIT 70 // Sets the max pwm power limit -#define POWER_LIMIT 0 // 0 watts default limit -#define MAX_POWER_LIMIT 65 // -#define POWER_LIMIT_STEPS 5 // -#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS100 -#define TEMP_uV_LOOKUP_HAKKO +#define VOLTAGE_DIV 467 // 467 - Default divider from schematic +#define CALIBRATION_OFFSET 900 // 900 - Default adc offset in uV +#define PID_POWER_LIMIT 70 // Sets the max pwm power limit +#define POWER_LIMIT 0 // 0 watts default limit +#define MAX_POWER_LIMIT 65 // +#define POWER_LIMIT_STEPS 5 // +#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS100 // +#define TEMP_uV_LOOKUP_HAKKO // +#define USB_PD_VMAX 20 // Maximum voltage for PD to negotiate #endif #ifdef MODEL_Pinecil -#define VOLTAGE_DIV 467 // 467 - Default divider from schematic -#define CALIBRATION_OFFSET 900 // 900 - Default adc offset in uV -#define PID_POWER_LIMIT 70 // Sets the max pwm power limit -#define POWER_LIMIT 0 // 0 watts default limit -#define MAX_POWER_LIMIT 65 // -#define POWER_LIMIT_STEPS 5 // -#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS100 -#define TEMP_uV_LOOKUP_HAKKO +#define VOLTAGE_DIV 467 // 467 - Default divider from schematic +#define CALIBRATION_OFFSET 900 // 900 - Default adc offset in uV +#define PID_POWER_LIMIT 70 // Sets the max pwm power limit +#define POWER_LIMIT 0 // 0 watts default limit +#define MAX_POWER_LIMIT 65 // +#define POWER_LIMIT_STEPS 5 // +#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS100 // Uses TS100 resistors +#define TEMP_uV_LOOKUP_HAKKO // Use Hakko lookup table +#define USB_PD_VMAX 20 // Maximum voltage for PD to negotiate #endif #ifdef MODEL_TS80 -#define VOLTAGE_DIV 780 // Default divider from schematic -#define PID_POWER_LIMIT 24 // Sets the max pwm power limit -#define CALIBRATION_OFFSET 900 // the adc offset in uV -#define POWER_LIMIT 24 // 24 watts default power limit -#define MAX_POWER_LIMIT 30 // -#define POWER_LIMIT_STEPS 2 -#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS80 -#define TEMP_uV_LOOKUP_TS80 +#define VOLTAGE_DIV 780 // Default divider from schematic +#define PID_POWER_LIMIT 24 // Sets the max pwm power limit +#define CALIBRATION_OFFSET 900 // the adc offset in uV +#define POWER_LIMIT 24 // 24 watts default power limit +#define MAX_POWER_LIMIT 30 // +#define POWER_LIMIT_STEPS 2 // +#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS80 // +#define TEMP_uV_LOOKUP_TS80 // +#define USB_PD_VMAX 12 // Maximum voltage for PD to negotiate #endif #ifdef MODEL_TS80P -#define VOLTAGE_DIV 650 // Default for TS80P with slightly different resistors -#define PID_POWER_LIMIT 35 // Sets the max pwm power limit -#define CALIBRATION_OFFSET 1500 // the adc offset in uV -#define POWER_LIMIT 30 // 30 watts default power limit -#define MAX_POWER_LIMIT 35 // -#define POWER_LIMIT_STEPS 2 -#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS80 -#define TEMP_uV_LOOKUP_TS80 +#define VOLTAGE_DIV 650 // Default for TS80P with slightly different resistors +#define PID_POWER_LIMIT 35 // Sets the max pwm power limit +#define CALIBRATION_OFFSET 1500 // the adc offset in uV +#define POWER_LIMIT 30 // 30 watts default power limit +#define MAX_POWER_LIMIT 35 // +#define POWER_LIMIT_STEPS 2 // +#define OP_AMP_GAIN_STAGE OP_AMP_GAIN_STAGE_TS80 // +#define TEMP_uV_LOOKUP_TS80 // +#define USB_PD_VMAX 12 // Maximum voltage for PD to negotiate #endif #ifdef MODEL_TS100 diff --git a/source/Core/Inc/power.hpp b/source/Core/Inc/power.hpp index ba25ef82..786fb979 100644 --- a/source/Core/Inc/power.hpp +++ b/source/Core/Inc/power.hpp @@ -5,8 +5,8 @@ * Authors: Ben V. Brown, David Hilton (David's Idea) */ -#include "../../configuration.h" #include "BSP.h" +#include "configuration.h" #include "expMovingAverage.h" #include "stdint.h" #include diff --git a/source/Core/Src/QC3.cpp b/source/Core/Src/QC3.cpp index 132ac11c..6a11c5de 100644 --- a/source/Core/Src/QC3.cpp +++ b/source/Core/Src/QC3.cpp @@ -81,12 +81,12 @@ void seekQC(int16_t Vx10, uint16_t divisor) { return; // dont bother with small steps while (steps < 0) { QC_SeekContNeg(); - osDelay(30); + vTaskDelay(3 * TICKS_10MS); steps++; } while (steps > 0) { QC_SeekContPlus(); - osDelay(30); + vTaskDelay(3 * TICKS_10MS); steps--; } osDelay(100); @@ -140,7 +140,7 @@ void startQC(uint16_t divisor) { // Delay 1.25 seconds uint8_t enteredQC = 0; for (uint16_t i = 0; i < 200 && enteredQC == 0; i++) { - osDelay(10); // 10mS pause + vTaskDelay(TICKS_10MS); // 10mS pause if (i > 130) { if (QC_DM_PulledDown()) { enteredQC = 1; @@ -165,7 +165,7 @@ void startQC(uint16_t divisor) { QCMode = QCState::QC_3; // We have at least QC2, pray for 3 return; } - osDelay(100); // 100mS + vTaskDelay(TICKS_100MS); // 100mS } QCMode = QCState::NOT_STARTED; QCTries++; diff --git a/source/Core/Src/Settings.cpp b/source/Core/Src/Settings.cpp index 70c112f8..358323f3 100644 --- a/source/Core/Src/Settings.cpp +++ b/source/Core/Src/Settings.cpp @@ -9,9 +9,9 @@ */ #include "Settings.h" -#include "../../configuration.h" #include "BSP.h" #include "Setup.h" +#include "configuration.h" #include "string.h" volatile systemSettingsType systemSettings; diff --git a/source/Core/Src/gui.cpp b/source/Core/Src/gui.cpp index 583b437c..2804f2bb 100644 --- a/source/Core/Src/gui.cpp +++ b/source/Core/Src/gui.cpp @@ -6,11 +6,11 @@ */ #include "gui.hpp" -#include "../../configuration.h" #include "Buttons.hpp" #include "TipThermoModel.h" #include "Translation.h" #include "cmsis_os.h" +#include "configuration.h" #include "main.hpp" void gui_Menu(const menuitem *menu); diff --git a/source/Core/Src/main.cpp b/source/Core/Src/main.cpp index 389005ca..1f3c2875 100644 --- a/source/Core/Src/main.cpp +++ b/source/Core/Src/main.cpp @@ -4,13 +4,11 @@ * Main.cpp bootstraps the device and then hands over to FreeRTOS and the threads */ +#include "main.hpp" #include "BSP.h" -#include "LIS2DH12.hpp" #include "Settings.h" #include "cmsis_os.h" -#include -#include -#include +#include "power.hpp" uint8_t DetectedAccelerometerVersion = 0; bool settingsWereReset = false; // FreeRTOS variables @@ -45,21 +43,23 @@ int main(void) { settingsWereReset = restoreSettings(); // load the settings from flash resetWatchdog(); /* Create the thread(s) */ - /* definition and creation of POWTask - Power management for QC */ - osThreadStaticDef(POWTask, startPOWTask, osPriorityAboveNormal, 0, POWTaskStackSize, POWTaskBuffer, &POWTaskControlBlock); - POWTaskHandle = osThreadCreate(osThread(POWTask), NULL); - - /* definition and creation of GUITask - The OLED control & update*/ - osThreadStaticDef(GUITask, startGUITask, osPriorityBelowNormal, 0, GUITaskStackSize, GUITaskBuffer, &GUITaskControlBlock); - GUITaskHandle = osThreadCreate(osThread(GUITask), NULL); /* definition and creation of PIDTask - Heating control*/ osThreadStaticDef(PIDTask, startPIDTask, osPriorityRealtime, 0, PIDTaskStackSize, PIDTaskBuffer, &PIDTaskControlBlock); PIDTaskHandle = osThreadCreate(osThread(PIDTask), NULL); + /* definition and creation of POWTask - Power management for QC */ + osThreadStaticDef(POWTask, startPOWTask, osPriorityAboveNormal, 0, POWTaskStackSize, POWTaskBuffer, &POWTaskControlBlock); + POWTaskHandle = osThreadCreate(osThread(POWTask), NULL); + /* definition and creation of MOVTask - Accelerometer management */ osThreadStaticDef(MOVTask, startMOVTask, osPriorityNormal, 0, MOVTaskStackSize, MOVTaskBuffer, &MOVTaskControlBlock); MOVTaskHandle = osThreadCreate(osThread(MOVTask), NULL); + + /* definition and creation of GUITask - The OLED control & update*/ + osThreadStaticDef(GUITask, startGUITask, osPriorityBelowNormal, 0, GUITaskStackSize, GUITaskBuffer, &GUITaskControlBlock); + GUITaskHandle = osThreadCreate(osThread(GUITask), NULL); + resetWatchdog(); /* Start scheduler */ diff --git a/source/Core/Threads/GUIThread.cpp b/source/Core/Threads/GUIThread.cpp index 54fd006c..8437c4dc 100644 --- a/source/Core/Threads/GUIThread.cpp +++ b/source/Core/Threads/GUIThread.cpp @@ -7,7 +7,6 @@ extern "C" { #include "FreeRTOSConfig.h" } -#include "../../configuration.h" #include "Buttons.hpp" #include "I2CBB.hpp" #include "LIS2DH12.hpp" @@ -15,6 +14,7 @@ extern "C" { #include "TipThermoModel.h" #include "Translation.h" #include "cmsis_os.h" +#include "configuration.h" #include "main.hpp" #include "stdlib.h" #include "string.h" diff --git a/source/Core/Threads/POWThread.cpp b/source/Core/Threads/POWThread.cpp index 2f5661e4..edb5d3c7 100644 --- a/source/Core/Threads/POWThread.cpp +++ b/source/Core/Threads/POWThread.cpp @@ -10,6 +10,7 @@ #include "QC3.h" #include "Settings.h" #include "cmsis_os.h" +#include "fusbpd.h" #include "main.hpp" #include "stdlib.h" #include "task.h" @@ -17,9 +18,20 @@ // Small worker thread to handle power (mostly QC) related steps void startPOWTask(void const *argument __unused) { + // You have to run this once we are willing to answer PD messages + // Setting up too early can mean that we miss the ~20ms window to respond on some chargers +#ifdef POW_PD + if (usb_pd_detect() == true) { + // Spawn all of the USB-C processors + fusb302_start_processing(); + } +#endif + vTaskDelay(TICKS_100MS); + // Init any other misc sensors postRToSInit(); + for (;;) { - osDelay(TICKS_100MS); // Slow down update rate power_check(); + osDelay(TICKS_100MS); // Slow down update rate } }