Implemented RX on Node
This commit is contained in:
@@ -63,6 +63,7 @@ target_link_libraries(i2c-hub-firmware
|
|||||||
# Add the standard include files to the build
|
# Add the standard include files to the build
|
||||||
target_include_directories(i2c-hub-firmware PRIVATE
|
target_include_directories(i2c-hub-firmware PRIVATE
|
||||||
${CMAKE_CURRENT_LIST_DIR}
|
${CMAKE_CURRENT_LIST_DIR}
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/include
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add any user requested libraries
|
# Add any user requested libraries
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -14,8 +14,10 @@ add_library(GobotRPC STATIC
|
|||||||
|
|
||||||
target_include_directories(GobotRPC PUBLIC
|
target_include_directories(GobotRPC PUBLIC
|
||||||
${CMAKE_CURRENT_LIST_DIR}/../include
|
${CMAKE_CURRENT_LIST_DIR}/../include
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../include/util
|
||||||
${CMAKE_CURRENT_LIST_DIR}/../include/ti
|
${CMAKE_CURRENT_LIST_DIR}/../include/ti
|
||||||
${CMAKE_CURRENT_LIST_DIR}/../../..
|
${CMAKE_CURRENT_LIST_DIR}/../../..
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../../../include
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(GobotRPC
|
target_link_libraries(GobotRPC
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
add_library(GobotRPC_Node_RP2040_I2C STATIC
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../node_interface/rp2040/i2c/init.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../node_interface/rp2040/i2c/rx_tx.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../crc16.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../protocol_base.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../node_interface/init.cpp
|
||||||
|
)
|
||||||
|
target_include_directories(GobotRPC_Node_RP2040_I2C PUBLIC
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../node_interface/include
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../include/util
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../../..
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(GobotRPC_Node_RP2040_I2C
|
||||||
|
FreeRTOS-Kernel-Heap4
|
||||||
|
pico_stdlib
|
||||||
|
hardware_i2c
|
||||||
|
hardware_irq
|
||||||
|
)
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include "crc16.hpp"
|
||||||
|
|
||||||
#define POLY 0x8408
|
#define POLY 0x8408
|
||||||
/*
|
/*
|
||||||
// 16 12 5
|
// 16 12 5
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ enum GobotRPCTypes {
|
|||||||
ERROR = 0b10
|
ERROR = 0b10
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GobotRPCPackage_Req_Vacum {
|
||||||
|
uint8_t enable : 8;
|
||||||
|
};
|
||||||
|
|
||||||
#define GobotRPC_Package_DATA_OFFSET 2
|
#define GobotRPC_Package_DATA_OFFSET 2
|
||||||
#define CALC_SIZE_GobotRPC_PACKAGE(data_len) (data_len + GobotRPC_Package_DATA_OFFSET + 2)
|
#define CALC_SIZE_GobotRPC_PACKAGE(data_len) (data_len + GobotRPC_Package_DATA_OFFSET + 2)
|
||||||
|
|
||||||
@@ -24,5 +28,6 @@ public:
|
|||||||
|
|
||||||
void assembleGobotRPCHeader(char * buffer, GobotRPCNumber number, GobotRPCTypes data_size, size_t);
|
void assembleGobotRPCHeader(char * buffer, GobotRPCNumber number, GobotRPCTypes data_size, size_t);
|
||||||
void assembleCRC(char * buffer, size_t data_len);
|
void assembleCRC(char * buffer, size_t data_len);
|
||||||
|
bool checkCRC(char * buffer, size_t data_len);
|
||||||
|
|
||||||
GobotRPCHeaderInfo extractGobotRPCHeader(char * buffer);
|
GobotRPCHeaderInfo extractGobotRPCHeader(char * buffer);
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "protocol.hpp"
|
||||||
|
#include "node_interface_hardware.hpp"
|
||||||
|
|
||||||
|
#include "FreeRTOSConfig.h"
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
#include "queue.h"
|
||||||
|
|
||||||
|
typedef void (*onPackageRxCallback)(void * args, char *data, uint16_t len, GobotRPCTypes type, GobotRPCNumber number);
|
||||||
|
|
||||||
|
class GobotRPC_NI {
|
||||||
|
private:
|
||||||
|
onPackageRxCallback onPackageRx;
|
||||||
|
void *onPackageRxArgs;
|
||||||
|
|
||||||
|
QueueHandle_t txQueue;
|
||||||
|
QueueHandle_t rxQueue;
|
||||||
|
TaskHandle_t rxTaskHandle;
|
||||||
|
|
||||||
|
unsigned int core;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GobotRPC_NI(unsigned int core, QueueHandle_t txQueue, QueueHandle_t rxQueue);
|
||||||
|
|
||||||
|
void registerOnPackageRxCallback(onPackageRxCallback callback, void *context);
|
||||||
|
void sendPackage(char *data, size_t len, GobotRPCTypes type, GobotRPCNumber number);
|
||||||
|
|
||||||
|
void rxTask();
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "FreeRTOSConfig.h"
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "queue.h"
|
||||||
|
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
#include "hardware/i2c.h"
|
||||||
|
#include "hardware/irq.h"
|
||||||
|
|
||||||
|
struct GobotRPC_NI_Package_Transport {
|
||||||
|
char data[32];
|
||||||
|
uint length;
|
||||||
|
uint index;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum I2C_WRITE_STATE {
|
||||||
|
I2C_WRITE_STATE_FIRST,
|
||||||
|
I2C_WRITE_STATE_LENGTH,
|
||||||
|
I2C_WRITE_STATE_DATA,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum I2C_READ_STATE {
|
||||||
|
I2C_READ_STAGE_FIRST,
|
||||||
|
I2C_READ_STAGE_DONE,
|
||||||
|
I2C_READ_STAGE_WIP,
|
||||||
|
I2C_READ_STAGE_INVALID
|
||||||
|
};
|
||||||
|
|
||||||
|
enum I2C_SLAVE_EVENT {
|
||||||
|
I2C_SLAVE_RECEIVE,
|
||||||
|
I2C_SLAVE_REQUEST,
|
||||||
|
I2C_SLAVE_FINISH
|
||||||
|
};
|
||||||
|
|
||||||
|
class GobotRPC_NI_Hardware {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GobotRPC_NI_Hardware_RP2040_I2C_PreTxQueues {
|
||||||
|
QueueHandle_t isrPreTxQueue;
|
||||||
|
QueueHandle_t isrTXQueue;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GobotRPC_NI_Hardware_RP2040_I2C : public GobotRPC_NI_Hardware {
|
||||||
|
uint core;
|
||||||
|
|
||||||
|
QueueHandle_t isrPreTxQueue;
|
||||||
|
QueueHandle_t isrTXQueue;
|
||||||
|
QueueHandle_t isrRXQueue;
|
||||||
|
TaskHandle_t preTxTaskHandle;
|
||||||
|
|
||||||
|
uint i2cSDA_PIN;
|
||||||
|
uint i2cSCL_PIN;
|
||||||
|
uint int_PIN;
|
||||||
|
uint8_t i2cAddress;
|
||||||
|
|
||||||
|
I2C_WRITE_STATE writeState = I2C_WRITE_STATE_FIRST;
|
||||||
|
I2C_READ_STATE readState = I2C_READ_STAGE_INVALID;
|
||||||
|
|
||||||
|
GobotRPC_NI_Package_Transport rxPackage;
|
||||||
|
GobotRPC_NI_Package_Transport txPackage;
|
||||||
|
|
||||||
|
public:
|
||||||
|
i2c_inst_t * i2c_inst;
|
||||||
|
|
||||||
|
GobotRPC_NI_Hardware_RP2040_I2C(
|
||||||
|
xQueueHandle TXQueue, xQueueHandle RXQueue, uint core,
|
||||||
|
i2c_inst_t * i2c_inst,
|
||||||
|
uint8_t i2cAddress,
|
||||||
|
uint i2cSDA_PIN, uint i2cSCL_PIN, uint int_PIN
|
||||||
|
);
|
||||||
|
|
||||||
|
void onI2CIRQ(I2C_SLAVE_EVENT event, BaseType_t * xHigherPriorityTaskWoken);
|
||||||
|
void preTxTask();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern GobotRPC_NI_Hardware_RP2040_I2C * g_gobotrpc_ni_hardware_rp2040_i2c;
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#include "node_interface.hpp"
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static void rxTaskFn(void *pvParameters) {
|
||||||
|
GobotRPC_NI *ni = (GobotRPC_NI *)pvParameters;
|
||||||
|
ni->rxTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
GobotRPC_NI::GobotRPC_NI(unsigned int core, QueueHandle_t txQueue, QueueHandle_t rxQueue) {
|
||||||
|
this->core = core;
|
||||||
|
|
||||||
|
this->txQueue = txQueue;
|
||||||
|
this->rxQueue = rxQueue;
|
||||||
|
|
||||||
|
this->onPackageRx = NULL;
|
||||||
|
this->onPackageRxArgs = NULL;
|
||||||
|
|
||||||
|
xTaskCreateAffinitySet(
|
||||||
|
rxTaskFn,
|
||||||
|
"GobotRPC_NI RX Task",
|
||||||
|
2048,
|
||||||
|
this,
|
||||||
|
4,
|
||||||
|
this->core,
|
||||||
|
&this->rxTaskHandle
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GobotRPC_NI::registerOnPackageRxCallback(onPackageRxCallback callback, void *context) {
|
||||||
|
this->onPackageRx = callback;
|
||||||
|
this->onPackageRxArgs = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GobotRPC_NI::rxTask() {
|
||||||
|
while (true) {
|
||||||
|
GobotRPC_NI_Package_Transport package;
|
||||||
|
|
||||||
|
if (xQueueReceive(this->rxQueue, &package, portMAX_DELAY) == pdTRUE) {
|
||||||
|
GobotRPCHeaderInfo header = extractGobotRPCHeader(package.data);
|
||||||
|
|
||||||
|
if(this->onPackageRx != NULL) {
|
||||||
|
if (!checkCRC(package.data, header.len)) {
|
||||||
|
volatile int a = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->onPackageRx(
|
||||||
|
onPackageRxArgs,
|
||||||
|
package.data + GobotRPC_Package_DATA_OFFSET,
|
||||||
|
header.len, header.type, header.number
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GobotRPC_NI::sendPackage(char *data, size_t len, GobotRPCTypes type, GobotRPCNumber number) {
|
||||||
|
GobotRPC_NI_Package_Transport package;
|
||||||
|
memcpy(package.data + GobotRPC_Package_DATA_OFFSET, data, len);
|
||||||
|
assembleGobotRPCHeader(package.data, number, type, len);
|
||||||
|
assembleCRC(package.data, len);
|
||||||
|
xQueueSend(this->txQueue, &package, portMAX_DELAY);
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
#include "node_interface_hardware.hpp"
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
#include "hardware/i2c.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
GobotRPC_NI_Hardware_RP2040_I2C * g_gobotrpc_ni_hardware_rp2040_i2c;
|
||||||
|
i2c_inst_t * g_i2c_inst;
|
||||||
|
bool g_transfer_in_progress = false;
|
||||||
|
|
||||||
|
static void finish_transfer(BaseType_t * xHigherPriorityTaskWoken) {
|
||||||
|
if(g_transfer_in_progress) {
|
||||||
|
GobotRPC_NI_Hardware_RP2040_I2C * gobotrpc_ni = g_gobotrpc_ni_hardware_rp2040_i2c;
|
||||||
|
g_transfer_in_progress = false;
|
||||||
|
gobotrpc_ni->onI2CIRQ(I2C_SLAVE_FINISH, xHigherPriorityTaskWoken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void i2c_isr() {
|
||||||
|
GobotRPC_NI_Hardware_RP2040_I2C * gobotrpc_ni = g_gobotrpc_ni_hardware_rp2040_i2c;
|
||||||
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
|
|
||||||
|
i2c_hw_t * hw = i2c_get_hw(g_i2c_inst);
|
||||||
|
uint32_t intr_stat = hw->intr_stat;
|
||||||
|
|
||||||
|
if (intr_stat == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intr_stat & I2C_IC_INTR_STAT_R_TX_ABRT_BITS) {
|
||||||
|
hw->clr_tx_abrt;
|
||||||
|
finish_transfer(&xHigherPriorityTaskWoken);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intr_stat & I2C_IC_INTR_STAT_R_START_DET_BITS) {
|
||||||
|
hw->clr_start_det;
|
||||||
|
finish_transfer(&xHigherPriorityTaskWoken);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intr_stat & I2C_IC_INTR_STAT_R_STOP_DET_BITS) {
|
||||||
|
hw->clr_stop_det;
|
||||||
|
finish_transfer(&xHigherPriorityTaskWoken);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intr_stat & I2C_IC_INTR_STAT_R_RX_FULL_BITS) {
|
||||||
|
g_transfer_in_progress = true;
|
||||||
|
gobotrpc_ni->onI2CIRQ(I2C_SLAVE_RECEIVE, &xHigherPriorityTaskWoken);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intr_stat & I2C_IC_INTR_STAT_R_RD_REQ_BITS) {
|
||||||
|
hw->clr_rd_req;
|
||||||
|
g_transfer_in_progress = true;
|
||||||
|
gobotrpc_ni->onI2CIRQ(I2C_SLAVE_REQUEST, &xHigherPriorityTaskWoken);
|
||||||
|
}
|
||||||
|
|
||||||
|
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void preTxTaskFn(void *pvParameters) {
|
||||||
|
GobotRPC_NI_Hardware_RP2040_I2C * hw = (GobotRPC_NI_Hardware_RP2040_I2C *)(pvParameters);
|
||||||
|
hw->preTxTask();
|
||||||
|
};
|
||||||
|
|
||||||
|
GobotRPC_NI_Hardware_RP2040_I2C::GobotRPC_NI_Hardware_RP2040_I2C(
|
||||||
|
xQueueHandle TXQueue, xQueueHandle RXQueue, uint core,
|
||||||
|
i2c_inst_t * i2c_inst,
|
||||||
|
uint8_t i2cAddress,
|
||||||
|
uint i2cSDA_PIN, uint i2cSCL_PIN, uint int_PIN
|
||||||
|
) {
|
||||||
|
g_gobotrpc_ni_hardware_rp2040_i2c = this;
|
||||||
|
g_i2c_inst = i2c_inst;
|
||||||
|
|
||||||
|
this->core = core;
|
||||||
|
|
||||||
|
this->isrRXQueue = RXQueue;
|
||||||
|
this->isrPreTxQueue = TXQueue;
|
||||||
|
this->isrTXQueue = xQueueCreate(3, sizeof(GobotRPC_NI_Package_Transport));
|
||||||
|
|
||||||
|
xTaskCreateAffinitySet(
|
||||||
|
preTxTaskFn,
|
||||||
|
"GobotRPC_NI Hardware RP2040 I2C PreTx Task",
|
||||||
|
2048,
|
||||||
|
this,
|
||||||
|
4,
|
||||||
|
this->core,
|
||||||
|
&this->preTxTaskHandle
|
||||||
|
);
|
||||||
|
|
||||||
|
this->i2cSDA_PIN = i2cSDA_PIN;
|
||||||
|
this->i2cSCL_PIN = i2cSCL_PIN;
|
||||||
|
this->int_PIN = int_PIN;
|
||||||
|
|
||||||
|
this->i2cAddress = i2cAddress;
|
||||||
|
this->i2c_inst = i2c_inst;
|
||||||
|
|
||||||
|
memset(&rxPackage.data, 0, sizeof(GobotRPC_NI_Package_Transport::data));
|
||||||
|
memset(&txPackage.data, 0, sizeof(GobotRPC_NI_Package_Transport::data));
|
||||||
|
|
||||||
|
gpio_init(i2cSDA_PIN);
|
||||||
|
gpio_init(i2cSCL_PIN);
|
||||||
|
gpio_set_function(i2cSDA_PIN, GPIO_FUNC_I2C);
|
||||||
|
gpio_set_function(i2cSCL_PIN, GPIO_FUNC_I2C);
|
||||||
|
|
||||||
|
gpio_init(int_PIN);
|
||||||
|
gpio_set_dir(int_PIN, GPIO_OUT);
|
||||||
|
gpio_put(int_PIN, 0);
|
||||||
|
|
||||||
|
// Note: The I2C slave does clock stretching implicitly after a RD_REQ, while the Tx FIFO is empty.
|
||||||
|
// There is also an option to enable clock stretching while the Rx FIFO is full, but we leave it
|
||||||
|
// disabled since the Rx FIFO should never fill up (unless slave->handler() is way too slow).
|
||||||
|
i2c_set_slave_mode(i2c_inst, true, i2cAddress);
|
||||||
|
|
||||||
|
i2c_hw_t *hw = i2c_get_hw(i2c_inst);
|
||||||
|
// unmask necessary interrupts
|
||||||
|
hw->intr_mask = I2C_IC_INTR_MASK_M_RX_FULL_BITS |\
|
||||||
|
I2C_IC_INTR_MASK_M_RD_REQ_BITS |\
|
||||||
|
I2C_IC_RAW_INTR_STAT_TX_ABRT_BITS |\
|
||||||
|
I2C_IC_INTR_MASK_M_STOP_DET_BITS |\
|
||||||
|
I2C_IC_INTR_MASK_M_START_DET_BITS;
|
||||||
|
|
||||||
|
// enable interrupt for current core
|
||||||
|
unsigned int intNum = i2c_inst == i2c0 ? I2C0_IRQ : I2C1_IRQ;
|
||||||
|
irq_set_exclusive_handler(intNum, i2c_isr);
|
||||||
|
irq_set_enabled(intNum, true);
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
#include "node_interface_hardware.hpp"
|
||||||
|
#include "hardware/irq.h"
|
||||||
|
|
||||||
|
void GobotRPC_NI_Hardware_RP2040_I2C::onI2CIRQ(I2C_SLAVE_EVENT event, BaseType_t * xHigherPriorityTaskWoken) {
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case I2C_SLAVE_RECEIVE: { // I2C Write from Master
|
||||||
|
char data = i2c_read_byte_raw(i2c_inst);
|
||||||
|
|
||||||
|
switch (writeState) {
|
||||||
|
case I2C_WRITE_STATE_FIRST:
|
||||||
|
writeState = I2C_WRITE_STATE_LENGTH;
|
||||||
|
rxPackage.index = 0;
|
||||||
|
rxPackage.length = 0;
|
||||||
|
rxPackage.data[rxPackage.index++] = data;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case I2C_WRITE_STATE_LENGTH:
|
||||||
|
rxPackage.data[rxPackage.index++] = data;
|
||||||
|
rxPackage.length = data;
|
||||||
|
writeState = I2C_WRITE_STATE_DATA;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case I2C_WRITE_STATE_DATA:
|
||||||
|
rxPackage.data[rxPackage.index++] = data;
|
||||||
|
|
||||||
|
if(rxPackage.index == rxPackage.length) {
|
||||||
|
xQueueSendFromISR(isrRXQueue, &rxPackage, xHigherPriorityTaskWoken);
|
||||||
|
writeState = I2C_WRITE_STATE_FIRST;
|
||||||
|
} else {
|
||||||
|
writeState = I2C_WRITE_STATE_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case I2C_SLAVE_REQUEST: { // I2C Read from Master
|
||||||
|
if(xQueueIsQueueEmptyFromISR(isrTXQueue) == pdFALSE) {
|
||||||
|
readState = I2C_READ_STAGE_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (readState) {
|
||||||
|
case I2C_READ_STAGE_INVALID:
|
||||||
|
i2c_write_byte_raw(i2c_inst, 0x00);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case I2C_READ_STAGE_FIRST:
|
||||||
|
xQueueReceiveFromISR(isrTXQueue, &txPackage, xHigherPriorityTaskWoken);
|
||||||
|
txPackage.index = 0;
|
||||||
|
i2c_write_byte_raw(i2c_inst, txPackage.data[txPackage.index++]);
|
||||||
|
readState = I2C_READ_STAGE_WIP;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case I2C_READ_STAGE_WIP:
|
||||||
|
if(txPackage.index == txPackage.length - 1) {
|
||||||
|
readState = I2C_READ_STAGE_DONE;
|
||||||
|
} else {
|
||||||
|
i2c_write_byte_raw(i2c_inst, txPackage.data[txPackage.index++]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case I2C_READ_STAGE_DONE:
|
||||||
|
i2c_write_byte_raw(i2c_inst, 0x00);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case I2C_SLAVE_FINISH:
|
||||||
|
writeState = I2C_WRITE_STATE_FIRST;
|
||||||
|
readState = I2C_READ_STAGE_FIRST;
|
||||||
|
rxPackage.index = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GobotRPC_NI_Hardware_RP2040_I2C::preTxTask() {
|
||||||
|
GobotRPC_NI_Package_Transport pkg;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
xQueueReceive(isrPreTxQueue, &pkg, portMAX_DELAY);
|
||||||
|
xQueueSend(isrTXQueue, &pkg, portMAX_DELAY);
|
||||||
|
gpio_put(int_PIN, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,3 +23,9 @@ void assembleCRC(char * buffer, size_t data_len) {
|
|||||||
buffer[GobotRPC_Package_DATA_OFFSET + data_len + 1] = crc & 0xff;
|
buffer[GobotRPC_Package_DATA_OFFSET + data_len + 1] = crc & 0xff;
|
||||||
buffer[GobotRPC_Package_DATA_OFFSET + data_len + 0] = (crc >> 8) & 0xff;
|
buffer[GobotRPC_Package_DATA_OFFSET + data_len + 0] = (crc >> 8) & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool checkCRC(char * buffer, size_t data_len) {
|
||||||
|
unsigned short crc = crc16(buffer, data_len - 2);
|
||||||
|
unsigned short crc_received = buffer[data_len - GobotRPC_Package_DATA_OFFSET + 1] | (buffer[data_len - GobotRPC_Package_DATA_OFFSET + 0] << 8);
|
||||||
|
return crc == crc_received;
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ void GobotRPC_TI_Hardware_RP2040_I2C::i2cTxTask() {
|
|||||||
pullPackageCB(&pkg, pullPackageCBArgs);
|
pullPackageCB(&pkg, pullPackageCBArgs);
|
||||||
|
|
||||||
xSemaphoreTake(i2cMutex, portMAX_DELAY);
|
xSemaphoreTake(i2cMutex, portMAX_DELAY);
|
||||||
unsigned int res = i2c_write_burst_blocking(i2c, pkg.addr & 0x7f, (uint8_t *)(&pkg.data), pkg.len);
|
unsigned int res = i2c_write_blocking(i2c, pkg.addr & 0x7f, (uint8_t * )(pkg.data), pkg.len, false);
|
||||||
xSemaphoreGive(i2cMutex);
|
xSemaphoreGive(i2cMutex);
|
||||||
|
|
||||||
if(res == PICO_ERROR_GENERIC) {
|
if(res == PICO_ERROR_GENERIC) {
|
||||||
|
|||||||
BIN
i2c-hub/pulseview-i2c-session
Normal file
BIN
i2c-hub/pulseview-i2c-session
Normal file
Binary file not shown.
1
motor-control/core-xy-firmware/lib/gobotrpc
Symbolic link
1
motor-control/core-xy-firmware/lib/gobotrpc
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
/home/alexander/Projects/gobot/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc
|
||||||
@@ -7,8 +7,8 @@
|
|||||||
"${userHome}/.pico-sdk/sdk/2.1.0/**"
|
"${userHome}/.pico-sdk/sdk/2.1.0/**"
|
||||||
],
|
],
|
||||||
"forcedInclude": [
|
"forcedInclude": [
|
||||||
"${userHome}/.pico-sdk/sdk/2.1.0/src/common/pico_base_headers/include/pico.h",
|
"${workspaceFolder}/build/generated/pico_base/pico/config_autogen.h",
|
||||||
"${workspaceFolder}/build/generated/pico_base/pico/config_autogen.h"
|
"${userHome}/.pico-sdk/sdk/2.1.0/src/common/pico_base_headers/include/pico.h"
|
||||||
],
|
],
|
||||||
"defines": [],
|
"defines": [],
|
||||||
"compilerPath": "${userHome}/.pico-sdk/toolchain/13_3_Rel1/bin/arm-none-eabi-gcc",
|
"compilerPath": "${userHome}/.pico-sdk/toolchain/13_3_Rel1/bin/arm-none-eabi-gcc",
|
||||||
|
|||||||
@@ -9,8 +9,12 @@
|
|||||||
"args": ["-C", "${workspaceFolder}/build"],
|
"args": ["-C", "${workspaceFolder}/build"],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"presentation": {
|
"presentation": {
|
||||||
|
"echo": true,
|
||||||
"reveal": "always",
|
"reveal": "always",
|
||||||
"panel": "dedicated"
|
"focus": true,
|
||||||
|
"panel": "dedicated",
|
||||||
|
"showReuseMessage": true,
|
||||||
|
"clear": true
|
||||||
},
|
},
|
||||||
"problemMatcher": "$gcc",
|
"problemMatcher": "$gcc",
|
||||||
"windows": {
|
"windows": {
|
||||||
@@ -27,8 +31,12 @@
|
|||||||
"-fx"
|
"-fx"
|
||||||
],
|
],
|
||||||
"presentation": {
|
"presentation": {
|
||||||
|
"echo": true,
|
||||||
"reveal": "always",
|
"reveal": "always",
|
||||||
"panel": "dedicated"
|
"focus": true,
|
||||||
|
"panel": "shared",
|
||||||
|
"showReuseMessage": true,
|
||||||
|
"clear": true
|
||||||
},
|
},
|
||||||
"problemMatcher": [],
|
"problemMatcher": [],
|
||||||
"windows": {
|
"windows": {
|
||||||
@@ -39,16 +47,51 @@
|
|||||||
"label": "Flash",
|
"label": "Flash",
|
||||||
"type": "process",
|
"type": "process",
|
||||||
"command": "${userHome}/.pico-sdk/openocd/0.12.0+dev/openocd.exe",
|
"command": "${userHome}/.pico-sdk/openocd/0.12.0+dev/openocd.exe",
|
||||||
|
"args": [
|
||||||
|
"-s",
|
||||||
|
"${userHome}/.pico-sdk/openocd/0.12.0+dev/scripts",
|
||||||
|
"-f", "interface/cmsis-dap.cfg",
|
||||||
|
"-f", "target/${command:raspberry-pi-pico.getTarget}.cfg",
|
||||||
|
"-c", "adapter speed 5000; program \"${command:raspberry-pi-pico.launchTargetPath}\" reset exit",
|
||||||
|
|
||||||
|
],
|
||||||
|
"presentation": {
|
||||||
|
"echo": true,
|
||||||
|
"reveal": "always",
|
||||||
|
"focus": true,
|
||||||
|
"panel": "shared",
|
||||||
|
"showReuseMessage": true,
|
||||||
|
"clear": true
|
||||||
|
},
|
||||||
|
"dependsOn": ["Compile Project"],
|
||||||
|
"problemMatcher": [],
|
||||||
|
"windows": {
|
||||||
|
"command": "${env:USERPROFILE}/.pico-sdk/openocd/0.12.0+dev/openocd.exe",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Reset",
|
||||||
|
"type": "process",
|
||||||
|
"command": "${userHome}/.pico-sdk/openocd/0.12.0+dev/openocd.exe",
|
||||||
"args": [
|
"args": [
|
||||||
"-s",
|
"-s",
|
||||||
"${userHome}/.pico-sdk/openocd/0.12.0+dev/scripts",
|
"${userHome}/.pico-sdk/openocd/0.12.0+dev/scripts",
|
||||||
"-f",
|
"-f",
|
||||||
"interface/cmsis-dap.cfg",
|
"interface/cmsis-dap.cfg",
|
||||||
"-f",
|
"-f", "target/${command:raspberry-pi-pico.getTarget}.cfg",
|
||||||
"target/${command:raspberry-pi-pico.getTarget}.cfg",
|
"-c", "adapter speed 5000; init; reset halt;",
|
||||||
"-c",
|
"-c", "rp2040.core1 arp_reset assert 0",
|
||||||
"adapter speed 5000; program \"${command:raspberry-pi-pico.launchTargetPath}\" verify reset exit"
|
"-c", "rp2040.core0 arp_reset assert 0",
|
||||||
|
"-c", "exit"
|
||||||
],
|
],
|
||||||
|
"presentation": {
|
||||||
|
"echo": true,
|
||||||
|
"reveal": "always",
|
||||||
|
"focus": true,
|
||||||
|
"panel": "shared",
|
||||||
|
"showReuseMessage": true,
|
||||||
|
"clear": true
|
||||||
|
},
|
||||||
"problemMatcher": [],
|
"problemMatcher": [],
|
||||||
"windows": {
|
"windows": {
|
||||||
"command": "${env:USERPROFILE}/.pico-sdk/openocd/0.12.0+dev/openocd.exe",
|
"command": "${env:USERPROFILE}/.pico-sdk/openocd/0.12.0+dev/openocd.exe",
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ project(vacum-control-firmware C CXX ASM)
|
|||||||
set(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/lib/FreeRTOS-Kernel)
|
set(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/lib/FreeRTOS-Kernel)
|
||||||
include(cmake/FreeRTOS_Kernel_import.cmake)
|
include(cmake/FreeRTOS_Kernel_import.cmake)
|
||||||
|
|
||||||
|
# Adding GobotRPC Node Library
|
||||||
|
include(lib/gobotrpc/cmake/gobotRPC_Node.cmake)
|
||||||
|
|
||||||
# Initialise the Raspberry Pi Pico SDK
|
# Initialise the Raspberry Pi Pico SDK
|
||||||
pico_sdk_init()
|
pico_sdk_init()
|
||||||
|
|
||||||
@@ -54,6 +57,7 @@ pico_enable_stdio_usb(vacum-control-firmware 0)
|
|||||||
# Add the standard library to the build
|
# Add the standard library to the build
|
||||||
target_link_libraries(vacum-control-firmware
|
target_link_libraries(vacum-control-firmware
|
||||||
pico_stdlib
|
pico_stdlib
|
||||||
|
GobotRPC_Node_RP2040_I2C
|
||||||
FreeRTOS-Kernel-Heap4
|
FreeRTOS-Kernel-Heap4
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -72,8 +72,8 @@
|
|||||||
/* Memory allocation related definitions. */
|
/* Memory allocation related definitions. */
|
||||||
#define configSUPPORT_STATIC_ALLOCATION 0
|
#define configSUPPORT_STATIC_ALLOCATION 0
|
||||||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||||
#define configTOTAL_HEAP_SIZE (1024 * 64)
|
#define configTOTAL_HEAP_SIZE (1024 * 128)
|
||||||
#define configAPPLICATION_ALLOCATED_HEAP (1024 * 32)
|
#define configAPPLICATION_ALLOCATED_HEAP (1024 * 64)
|
||||||
|
|
||||||
/* Hook function related definitions. */
|
/* Hook function related definitions. */
|
||||||
#define configCHECK_FOR_STACK_OVERFLOW 0
|
#define configCHECK_FOR_STACK_OVERFLOW 0
|
||||||
@@ -104,11 +104,11 @@
|
|||||||
|
|
||||||
#if FREE_RTOS_KERNEL_SMP // set by the RP2040 SMP port of FreeRTOS
|
#if FREE_RTOS_KERNEL_SMP // set by the RP2040 SMP port of FreeRTOS
|
||||||
/* SMP port only */
|
/* SMP port only */
|
||||||
#define configUSE_PASSIVE_IDLE_HOOK 0
|
#define configNUMBER_OF_CORES 2
|
||||||
#define configNUMBER_OF_CORES 1
|
|
||||||
#define configTICK_CORE 0
|
#define configTICK_CORE 0
|
||||||
#define configRUN_MULTIPLE_PRIORITIES 1
|
#define configRUN_MULTIPLE_PRIORITIES 1
|
||||||
//#define configUSE_CORE_AFFINITY 1
|
#define configUSE_CORE_AFFINITY 1
|
||||||
|
#define configUSE_PASSIVE_IDLE_HOOK 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* RP2040 specific */
|
/* RP2040 specific */
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#define CORE_MASK_GOBOTRPC 0b10
|
||||||
|
#define CORE_MASK_VACUM 0b01
|
||||||
|
|
||||||
#define LED1_PIN 16
|
#define LED1_PIN 16
|
||||||
#define LED2_PIN 25
|
#define LED2_PIN 25
|
||||||
|
|
||||||
#define RELAY_PIN 15
|
#define RELAY_PIN 15
|
||||||
|
|
||||||
#define GORPC_INT_PIN 3
|
#define GORPC_INT_PIN 2
|
||||||
#define GORPC_SDA_PIN 4
|
#define GORPC_SDA_PIN 4
|
||||||
#define GORPC_SCL_PIN 5
|
#define GORPC_SCL_PIN 5
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "pinConfig.hpp"
|
#include "pinConfigNode.hpp"
|
||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
#include "semphr.h"
|
#include "semphr.h"
|
||||||
@@ -9,6 +9,7 @@ void vButtonTaskFn(void *pvParameters);
|
|||||||
|
|
||||||
class VacumControl {
|
class VacumControl {
|
||||||
private:
|
private:
|
||||||
|
uint coreMask;
|
||||||
bool state = false;
|
bool state = false;
|
||||||
xSemaphoreHandle vacumMutex;
|
xSemaphoreHandle vacumMutex;
|
||||||
xSemaphoreHandle interruptionSemaphore;
|
xSemaphoreHandle interruptionSemaphore;
|
||||||
@@ -16,7 +17,7 @@ private:
|
|||||||
xTaskHandle interruptionTask;
|
xTaskHandle interruptionTask;
|
||||||
xTaskHandle buttonTask;
|
xTaskHandle buttonTask;
|
||||||
public:
|
public:
|
||||||
VacumControl();
|
VacumControl(uint coreMask);
|
||||||
|
|
||||||
void initVacumPins();
|
void initVacumPins();
|
||||||
void setState(bool on);
|
void setState(bool on);
|
||||||
|
|||||||
1
vacum-control/vacum-control-firmware/lib/gobotrpc
Symbolic link
1
vacum-control/vacum-control-firmware/lib/gobotrpc
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
/home/alexander/Projects/gobot/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "vacum.hpp"
|
#include "vacum.hpp"
|
||||||
#include "pinConfig.hpp"
|
#include "pinConfigNode.hpp"
|
||||||
|
|
||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
@@ -17,13 +17,14 @@ void vButtonTaskFn(void *pvParameters) {
|
|||||||
vacumControl->buttonTaskFn();
|
vacumControl->buttonTaskFn();
|
||||||
}
|
}
|
||||||
|
|
||||||
VacumControl::VacumControl() {
|
VacumControl::VacumControl(uint coreMask) {
|
||||||
|
this->coreMask = coreMask;
|
||||||
initVacumPins();
|
initVacumPins();
|
||||||
state = false;
|
state = false;
|
||||||
vacumMutex = xSemaphoreCreateMutex();
|
vacumMutex = xSemaphoreCreateMutex();
|
||||||
interruptionSemaphore = xSemaphoreCreateBinary();
|
interruptionSemaphore = xSemaphoreCreateBinary();
|
||||||
xTaskCreate(vInterruptionTaskFn, "Interruption Task", 1024, this, 3, &interruptionTask);
|
xTaskCreateAffinitySet(vInterruptionTaskFn, "Interruption Task", 1024, this, 3, coreMask, &interruptionTask);
|
||||||
xTaskCreate(vButtonTaskFn, "Button Task", 1024, this, 2, &buttonTask);
|
xTaskCreateAffinitySet(vButtonTaskFn, "Button Task", 1024, this, 2, coreMask, &buttonTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VacumControl::initVacumPins() {
|
void VacumControl::initVacumPins() {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include "pico/stdlib.h"
|
#include "pico/stdlib.h"
|
||||||
|
|
||||||
#include "vacum.hpp"
|
#include "vacum.hpp"
|
||||||
@@ -6,22 +7,88 @@
|
|||||||
#include "FreeRTOSConfig.h"
|
#include "FreeRTOSConfig.h"
|
||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
|
#include "queue.h"
|
||||||
|
|
||||||
|
#include "hardware/i2c.h"
|
||||||
|
|
||||||
|
#include "pinConfigNode.hpp"
|
||||||
|
#include "node_interface_hardware.hpp"
|
||||||
|
#include "node_interface.hpp"
|
||||||
|
#include "protocol.hpp"
|
||||||
|
|
||||||
|
struct AppData {
|
||||||
|
xQueueHandle txQueue;
|
||||||
|
xQueueHandle rxQueue;
|
||||||
|
VacumControl * vacumControl;
|
||||||
|
GobotRPC_NI * gobotrpc_ni;
|
||||||
|
};
|
||||||
|
|
||||||
|
AppData g_appData;
|
||||||
|
|
||||||
|
void onRxPackage(void * args, char *data, uint16_t len, GobotRPCTypes type, GobotRPCNumber number) {
|
||||||
|
AppData * appData = (AppData *) args;
|
||||||
|
char txBuffer[32];
|
||||||
|
|
||||||
|
switch (number) {
|
||||||
|
case GobotRPCNumber::VACUM: {
|
||||||
|
GobotRPCPackage_Req_Vacum * pkg = (GobotRPCPackage_Req_Vacum *) data;
|
||||||
|
appData->vacumControl->setState(pkg->enable);
|
||||||
|
g_appData.gobotrpc_ni->sendPackage(txBuffer, 0, GobotRPCTypes::RESPONSE, GobotRPCNumber::VACUM);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void core1_main(void *pvParameters) {
|
||||||
|
AppData * appData = (AppData *) pvParameters;
|
||||||
|
GobotRPC_NI_Hardware_RP2040_I2C gobotrpc_ni_hardware(
|
||||||
|
appData->txQueue, appData->rxQueue, CORE_MASK_VACUM,
|
||||||
|
i2c0, 0x21, GORPC_SDA_PIN, GORPC_SCL_PIN, GORPC_INT_PIN
|
||||||
|
);
|
||||||
|
|
||||||
void vTaskFunction(void *pvParameters) {
|
|
||||||
while (true) {
|
while (true) {
|
||||||
printf("Button: %d\n", gpio_get(BUTTON_PIN));
|
gpio_put(LED2_PIN, 0);
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
|
gpio_put(LED2_PIN, 1);
|
||||||
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TaskHandle_t xCore0TaskHandle = NULL;
|
||||||
|
TaskHandle_t xCore1TaskHandle = NULL;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
stdio_init_all();
|
stdio_init_all();
|
||||||
printf("Hello, world!\n");
|
printf("Hello, world!\n");
|
||||||
|
|
||||||
VacumControl vacumControl;
|
gpio_init(LED1_PIN);
|
||||||
vacumControl.setState(false);
|
gpio_set_dir(LED1_PIN, GPIO_OUT);
|
||||||
|
gpio_put(LED1_PIN, 1);
|
||||||
|
|
||||||
|
gpio_init(LED2_PIN);
|
||||||
|
gpio_set_dir(LED2_PIN, GPIO_OUT);
|
||||||
|
gpio_put(LED2_PIN, 1);
|
||||||
|
|
||||||
|
g_appData.txQueue = xQueueCreate(16, sizeof(GobotRPC_NI_Package_Transport));
|
||||||
|
g_appData.rxQueue = xQueueCreate(16, sizeof(GobotRPC_NI_Package_Transport));
|
||||||
|
|
||||||
|
VacumControl vacumControl = VacumControl(CORE_MASK_VACUM);
|
||||||
|
vacumControl.setState(false);
|
||||||
|
g_appData.vacumControl = &vacumControl;
|
||||||
|
|
||||||
|
GobotRPC_NI gobotrpc_ni(CORE_MASK_VACUM, g_appData.txQueue, g_appData.rxQueue);
|
||||||
|
gobotrpc_ni.registerOnPackageRxCallback(onRxPackage, &g_appData);
|
||||||
|
|
||||||
|
g_appData.gobotrpc_ni = &gobotrpc_ni;
|
||||||
|
|
||||||
|
xTaskCreateAffinitySet(
|
||||||
|
core1_main, "Core 1 Main", 2048, &g_appData, 1, CORE_MASK_VACUM, &xCore1TaskHandle
|
||||||
|
);
|
||||||
|
|
||||||
xTaskCreate(vTaskFunction, "Main Task", 1024, NULL, tskIDLE_PRIORITY, NULL);
|
|
||||||
vTaskStartScheduler();
|
vTaskStartScheduler();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|||||||
Reference in New Issue
Block a user