Related
I constantly get this error, no matter what I'm doing... I have an ILI9488 with 4-wire SPI and a GT911 capacitive Touch driver on an ESP32 (2MB, no PSRAM, arduino core).
this is my main.ino-file:
#include <lvgl.h>
#include <TFT_eSPI.h>
#include <Wire.h>
#include "Goodix.h"
#define INT_PIN 26
#define RST_PIN 15
#define SDA_PIN 22
#define SCL_PIN 16
Goodix touch = Goodix();
#define DISPLAY_BUF_SIZE 480 * 10
static uint16_t display_widht = 480;
static uint16_t display_height = 320;
TFT_eSPI tft = TFT_eSPI(); /* TFT instance */
bool touched = false;
GTPoint touchDat;
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[ DISPLAY_BUF_SIZE];
lv_disp_drv_t disp_drv; //display driver
lv_indev_drv_t touch_drv; //touchpad driver
void my_disp_flush( lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p ){
uint32_t w = ( area->x2 - area->x1 + 1 );
uint32_t h = ( area->y2 - area->y1 + 1 );
tft.startWrite();
tft.setAddrWindow( area->x1, area->y1, w, h );
tft.pushColors( ( uint16_t * )&color_p->full, w * h, true );
tft.endWrite();
lv_disp_flush_ready( disp );
}
void handleTouch(int8_t contacts, GTPoint* points) {
Serial.printf("Contacts: %d\n", contacts);
if(contacts > 0) touched = true;
else touched = false;
for (uint8_t i = 0; i < contacts; i++) {
touchDat = points[0];
Serial.printf("C%d: %d %d \n", points[i].trackId, points[i].x, points[i].y);
}
}
/*Read the touchpad*/
void my_touchpad_read( lv_indev_drv_t * touch_drv, lv_indev_data_t * data ){
if( !touched ) //kein Touch
{
data->state = LV_INDEV_STATE_REL;
}
else //touch!
{
data->state = LV_INDEV_STATE_PR;
/*Set the coordinates*/
data->point.x = touchDat.x;
data->point.y = touchDat.y;
}
}
void i2cInit(){
Wire.setPins(SDA_PIN, SCL_PIN);
Wire.setClock(400000);
Wire.begin();
delay(100);
}
void touchInit() {
touch.setHandler(handleTouch);
touch.setRes(display_widht, display_height);
touch.setRotation(3);
touch.begin(INT_PIN, RST_PIN, GOODIX_I2C_ADDR_28);
Serial.print("Check ACK on addr request on 0x");
Serial.print(touch.i2cAddr, HEX);
Wire.beginTransmission(touch.i2cAddr);
if (!Wire.endTransmission()) {
Serial.println(": SUCCESS");
} else {
Serial.print(": ERROR!");
}
}
void tftInit(){
tft.begin();
tft.setRotation(3);
lv_disp_draw_buf_init( &draw_buf, buf, NULL, DISPLAY_BUF_SIZE ); //init draw Buffer
/*Initialize the display*/
static lv_disp_drv_t disp_drv;
lv_disp_drv_init( &disp_drv );
/*Change the following line to your display resolution*/
disp_drv.hor_res = display_widht;
disp_drv.ver_res = display_height;
disp_drv.flush_cb = my_disp_flush;
disp_drv.draw_buf = &draw_buf;
lv_disp_drv_register( &disp_drv );
/*Initialize the input device driver*/
static lv_indev_drv_t touch_drv;
lv_indev_drv_init( &touch_drv );
touch_drv.type = LV_INDEV_TYPE_POINTER;
touch_drv.read_cb = my_touchpad_read;
lv_indev_drv_register( &touch_drv );
//create simple label
lv_obj_t *label = lv_label_create( lv_scr_act() );
lv_label_set_text( label, "Hello World!!" );
lv_obj_align( label, LV_ALIGN_CENTER, 0, 0 );
}
void setup() {
Serial.begin(115200); /* prepare for possible serial debug */
i2cInit();
touchInit(); //initialize touch
lv_init();
}
void loop() {
touch.loop();
lv_task_handler(); /* let the GUI do its work */
delay(5);
}
these are my main.ino and lv_config.h-files:
https://gist.github.com/kokospalme/a65448c1d10704066b9c6d2350c84a6d
even if I change LV_MEM_SIZE to something small like 1 or 10, I get the error, that " region `dram0_0_seg' overflowed by 22272 bytes". What am I doing wrong?
I'm trying to use GPT to measuring frequency on a gpio. After some research on the google and Linux's documentation, unfortunately I couldn't see any compatible GPT driver in kernel. I found a patch on google and applied it. But I have a getting clock error now. There is a function which It gets the clock but it's never executing.
P.S : I prepared a platform driver to use exported functions (e.g. mxc_request_input_capture) in timer-imx-gpt.c.
My dts nodes
/*These nodes are child node if aips1*/
gpt1: gpt#302d0000 {
compatible = "fsl,imx8mm-gpt";
reg = <0x302d0000 0x10000>;
interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MM_CLK_GPT1>,
<&clk IMX8MM_CLK_GPT1_ROOT>,
<&clk IMX8MM_CLK_GPT_3M>;
clock-names = "ipg", "per", "osc_per";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpt_input_capture0>;
status = "okay";
};
iomuxc: pinctrl#30330000 {
compatible = "fsl,imx8mm-iomuxc";
reg = <0x30330000 0x10000>;
pinctrl_gpt_input_capture0: gptinputcapture0grp {
fsl,pins = <
MX8MM_IOMUXC_SAI3_RXFS_GPT1_CAPTURE1 0xd6 /*0x00000000*/
>;
};
};
request gpt input capture func (in timer-imx-gpt.c)
int mxc_request_input_capture(unsigned int chan, mxc_icap_handler_t handler,
unsigned long capflags, void *dev_id)
{
struct imx_timer *imxtm;
struct icap_channel *ic;
unsigned long flags;
u64 start_cycles;
int ret = 0;
u32 mode;
/* we only care about rising and falling flags */
capflags &= (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING);
if (chan > 1 || !handler || !capflags)
return -EINVAL;
printk("mxc_request_input_capture 1\n");
ic = &icap_channel_arr[chan];
imxtm = ic->imxtm;
printk("mxc_request_input_capture 2\n");
if (!imxtm->gpt->gpt_ic_enable)
return -ENODEV; //THIS ERROR CODE RETURN
printk("mxc_request_input_capture 3\n");
spin_lock_irqsave(&icap_lock, flags);
if (ic->handler) {
ret = -EBUSY;
goto out;
}
printk("mxc_request_input_capture 4\n");
ic->handler = handler;
ic->dev_id = dev_id;
switch (capflags) {
case IRQF_TRIGGER_RISING:
mode = V2_IM_RISING;
break;
case IRQF_TRIGGER_FALLING:
mode = V2_IM_FALLING;
break;
default:
mode = V2_IM_BOTH;
break;
}
printk("mxc_request_input_capture 4\n");
/* ack any pending input capture interrupt before enabling */
imxtm->gpt->gpt_ic_irq_acknowledge(ic);
/*
* initialize the cyclecounter. The input capture is capturing
* from the mxc clocksource, so it has the same mask/shift/mult.
*/
memset(&ic->cc, 0, sizeof(ic->cc));
ic->cc.read = gpt_ic_read;
ic->cc.mask = clocksource_mxc.mask;
ic->cc.shift = clocksource_mxc.shift;
ic->cc.mult = clocksource_mxc.mult;
printk("mxc_request_input_capture 5\n");
/* initialize a timecounter for the input capture */
start_cycles = mxc_read_sched_clock();
timecounter_init(&ic->tc, &ic->cc, ktime_get_ns());
printk("mxc_request_input_capture 6\n");
/*
* timecounter_init() read the last captured timer count, but
* that's not the start cycle counter, so update it with the
* real start cycles.
*/
ic->tc.cycle_last = start_cycles;
imxtm->gpt->gpt_ic_enable(ic, mode);
imxtm->gpt->gpt_ic_irq_enable(ic);
printk("mxc_request_input_capture 7\n");
out:
spin_unlock_irqrestore(&icap_lock, flags);
printk("mxc_request_input_capture 8\n");
return ret;
}
EXPORT_SYMBOL_GPL(mxc_request_input_capture);
I realized that imxtm->gpt->gpt_ic_enable variable seems NULL. imxtm structure gets filled in the end of static int __init _mxc_timer_init function. But the function returns error before filling the struct. The error is happening checking the clock. The function which related to getting clock is mxc_timer_init_dt but it never executes.
log:
root:~# dmesg | grep gpt
[ 0.000174] gpt imx6dl_timer_init_dt HEAD
[ 0.000240] gpt _mxc_timer_init
[ 0.000244] gpt imxtm->type 3
[ 0.000249] gpt imxtm->type GPT_TYPE_IMX6DL
[ 0.000252] imx-gpt is NOT null
[ 0.000260] gpt GPT_TYPE_IMX6DL 3
[ 0.000263] gpt mxc_timer_init_dt error -517
[ 16.837810] mxc-timer 302d0000.gpt: GPT Timer Probe Function head
[ 16.843920] mxc-timer 302d0000.gpt: GPT Timer Probe Function end
It start with executing imx6dl_timer_init_dt. mxc_timer_init_dt function must be execute after imx6dl_timer_init_dt to get the clock but it is not executing. Due to failing on getting clock, I am not able to use the gpt module.
some parts of timer-imx-gpt.c
static int __init _mxc_timer_init(struct imx_timer *imxtm)
{
struct icap_channel *ic;
int i, ret;
printk(KERN_INFO "gpt _mxc_timer_init\n");
printk(KERN_INFO "gpt imxtm->type %d \n", imxtm->type);
switch (imxtm->type) {
case GPT_TYPE_IMX1:
imxtm->gpt = &imx1_gpt_data;
printk(KERN_INFO "gpt imxtm->type GPT_TYPE_IMX1 \n");
break;
case GPT_TYPE_IMX21:
imxtm->gpt = &imx21_gpt_data;
printk(KERN_INFO "gpt imxtm->type GPT_TYPE_IMX21 \n");
break;
case GPT_TYPE_IMX31:
imxtm->gpt = &imx31_gpt_data;
printk(KERN_INFO "gpt imxtm->type GPT_TYPE_IMX31 \n");
break;
case GPT_TYPE_IMX6DL:
imxtm->gpt = &imx6dl_gpt_data;
printk(KERN_INFO "gpt imxtm->type GPT_TYPE_IMX6DL \n");
break;
default:
printk(KERN_INFO "gpt imxtm->type DEFAULT \n");
return -EINVAL;
}
imxtm->gpt = &imx6dl_gpt_data;
if(!imxtm->gpt)
printk(KERN_INFO "imx-gpt is null");
printk(KERN_INFO "imx-gpt is NOT null");
if (IS_ERR(imxtm->clk_per)) {
pr_err("i.MX timer: unable to get clk\n"); //I SAW THIS LOG IN LINUX LOGS
return PTR_ERR(imxtm->clk_per); //Function return error at this line
}
printk(KERN_INFO "gpt clk_per success\n");
if (!IS_ERR(imxtm->clk_ipg))
clk_prepare_enable(imxtm->clk_ipg);
printk(KERN_INFO "gpt clk_ipg success\n");
clk_prepare_enable(imxtm->clk_per);
printk(KERN_INFO "gpt clk_prepare_enable\n");
/*
* Initialise to a known state (all timers off, and timing reset)
*/
writel_relaxed(0, imxtm->base + MXC_TCTL);
writel_relaxed(0, imxtm->base + MXC_TPRER); /* see datasheet note */
imxtm->gpt->gpt_oc_setup_tctl(imxtm);
/* init and register the timer to the framework */
ret = mxc_clocksource_init(imxtm);
if (ret)
return ret;
ret = mxc_clockevent_init(imxtm);
if (ret)
return ret;
/*Filling the imx structure. But never reach here*/
for (i = 0; i < 2; i++) {
ic = &icap_channel_arr[i];
ic->imxtm = imxtm;
}
printk(KERN_INFO, "_mxc_timer_init RETURN SUCCESS\n");
return 0;
}
void __init mxc_timer_init(unsigned long pbase, int irq, enum imx_gpt_type type)
{
struct imx_timer *imxtm;
printk(KERN_INFO, "gpt mxc_timer_init HEAD\n");
imxtm = kzalloc(sizeof(*imxtm), GFP_KERNEL);
BUG_ON(!imxtm);
imxtm->clk_per = clk_get_sys("imx-gpt.0", "per");
imxtm->clk_ipg = clk_get_sys("imx-gpt.0", "ipg");
imxtm->base = ioremap(pbase, SZ_4K);
BUG_ON(!imxtm->base);
imxtm->type = type;
imxtm->irq = irq;
_mxc_timer_init(imxtm);
}
/*
* a platform driver is needed in order to acquire pinmux
* for input capture pins. The probe call is also useful
* for setting up the input capture channel structures.
*/
static int mxc_timer_probe(struct platform_device *pdev)
{
struct icap_channel *ic;
int i;
dev_info(&pdev->dev, "GPT Timer Probe Function head\n");
/* setup the input capture channels */
for (i = 0; i < 2; i++) {
ic = &icap_channel_arr[i];
ic->chan = i;
if (i == 0) {
ic->cnt_reg = V2_TCAP1;
ic->irqen_bit = V2_IR_IF1;
ic->status_bit = V2_TSTAT_IF1;
ic->mode_bit = V2_TCTL_IM1_BIT;
} else {
ic->cnt_reg = V2_TCAP2;
ic->irqen_bit = V2_IR_IF2;
ic->status_bit = V2_TSTAT_IF2;
ic->mode_bit = V2_TCTL_IM2_BIT;
}
}
dev_info(&pdev->dev, "GPT Timer Probe Function end\n");
return 0;
}
static int mxc_timer_remove(struct platform_device *pdev)
{
return 0;
}
static const struct of_device_id timer_of_match[] = {
{ .compatible = "fsl,imx1-gpt" },
{ .compatible = "fsl,imx21-gpt" },
{ .compatible = "fsl,imx27-gpt" },
{ .compatible = "fsl,imx31-gpt" },
{ .compatible = "fsl,imx25-gpt" },
{ .compatible = "fsl,imx50-gpt" },
{ .compatible = "fsl,imx51-gpt" },
{ .compatible = "fsl,imx53-gpt" },
{ .compatible = "fsl,imx6q-gpt" },
{ .compatible = "fsl,imx6dl-gpt" },
{ .compatible = "fsl,imx6sl-gpt" },
{ .compatible = "fsl,imx6sx-gpt" },
{ .compatible = "fsl,imx8mm-gpt" },
{ },
};
MODULE_DEVICE_TABLE(of, timer_of_match);
static struct platform_driver mxc_timer_pdrv = {
.probe = mxc_timer_probe,
.remove = mxc_timer_remove,
.driver = {
.name = "mxc-timer",
.owner = THIS_MODULE,
.of_match_table = timer_of_match,
},
};
module_platform_driver(mxc_timer_pdrv);
static int __init mxc_timer_init_dt(struct device_node *np, enum imx_gpt_type type)
{
struct imx_timer *imxtm;
static int initialized;
int ret;
printk(KERN_INFO, "gpt mxc_timer_init_dt head\n");
/* Support one instance only */
if (initialized)
return 0;
imxtm = kzalloc(sizeof(*imxtm), GFP_KERNEL);
if (!imxtm)
return -ENOMEM;
imxtm->base = of_iomap(np, 0);
if (!imxtm->base)
return -ENXIO;
imxtm->irq = irq_of_parse_and_map(np, 0);
if (imxtm->irq <= 0)
return -EINVAL;
imxtm->clk_ipg = of_clk_get_by_name(np, "ipg");
/* Try osc_per first, and fall back to per otherwise */
imxtm->clk_per = of_clk_get_by_name(np, "osc_per");
if (IS_ERR(imxtm->clk_per))
imxtm->clk_per = of_clk_get_by_name(np, "per");
imxtm->type = type;
printk(KERN_INFO, "gpt mxc_timer_init_dt line 883\n");
ret = _mxc_timer_init(imxtm);
if (ret)
return ret;
initialized = 1;
printk(KERN_INFO, "gpt mxc_timer_init_dt end\n");
return 0;
}
static int __init imx1_timer_init_dt(struct device_node *np)
{
return mxc_timer_init_dt(np, GPT_TYPE_IMX1);
}
static int __init imx21_timer_init_dt(struct device_node *np)
{
return mxc_timer_init_dt(np, GPT_TYPE_IMX21);
}
static int __init imx31_timer_init_dt(struct device_node *np)
{
enum imx_gpt_type type = GPT_TYPE_IMX31;
printk(KERN_INFO "gpt imx31_timer_init_dt HEAD");
/*
* We were using the same compatible string for i.MX6Q/D and i.MX6DL/S
* GPT device, while they actually have different programming model.
* This is a workaround to keep the existing i.MX6DL/S DTBs continue
* working with the new kernel.
*/
if (of_machine_is_compatible("fsl,imx6dl"))
type = GPT_TYPE_IMX6DL;
return mxc_timer_init_dt(np, type);
}
static int __init imx6dl_timer_init_dt(struct device_node *np)
{
printk(KERN_INFO "gpt imx6dl_timer_init_dt HEAD");
return mxc_timer_init_dt(np, GPT_TYPE_IMX6DL); //This function must execute to get clock
}
TIMER_OF_DECLARE(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt);
TIMER_OF_DECLARE(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt);
TIMER_OF_DECLARE(imx27_timer, "fsl,imx27-gpt", imx21_timer_init_dt);
TIMER_OF_DECLARE(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt);
TIMER_OF_DECLARE(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt);
TIMER_OF_DECLARE(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt);
TIMER_OF_DECLARE(imx51_timer, "fsl,imx51-gpt", imx31_timer_init_dt);
TIMER_OF_DECLARE(imx53_timer, "fsl,imx53-gpt", imx31_timer_init_dt);
TIMER_OF_DECLARE(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt);
TIMER_OF_DECLARE(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt);
TIMER_OF_DECLARE(imx6sl_timer, "fsl,imx6sl-gpt", imx6dl_timer_init_dt);
TIMER_OF_DECLARE(imx6sx_timer, "fsl,imx6sx-gpt", imx6dl_timer_init_dt);
TIMER_OF_DECLARE(imx8mm_timer, "fsl,imx8mm-gpt", imx6dl_timer_init_dt); //This line added after applying patch
I will be very grateful for your help
I am programing my esp32 to be able to advertise my custom services/characteristics. I am failry new to esp idf and I am struggling to program bluetooth using nimBLE. during building,there is no error thrown but while monitoring, i receive the following error from the function in main:
I (391) heap_init: At 3FFB6388 len 00001C78 (7 KiB): DRAM
I (397) heap_init: At 3FFB9A20 len 00004108 (16 KiB): DRAM
I (403) heap_init: At 3FFC49F0 len 0001B610 (109 KiB): DRAM
I (409) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (415) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (422) heap_init: At 40096DB0 len 00009250 (36 KiB): IRAM
I (429) spi_flash: detected chip: generic
I (433) spi_flash: flash io: dio
I (438) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (484) BTDM_INIT: BT controller compile version [1342a48]
I (484) system_api: Base MAC address is not set
I (484) system_api: read default base MAC address from EFUSE
I (494) phy_init: phy_version 4670,719f9f6,Feb 18 2021,17:07:07
ESP_ERROR_CHECK failed: esp_err_t 0x3 (ERROR) at 0x4008e6f4
0x4008e6f4: _esp_error_check_failed at C:/Users/Kanimba/Desktop/esp-idf/components/esp_common/src/esp_err.c:41
file: "../main/main.c" line 35
func: app_main
expression: gatt_svrs_init()
abort() was called at PC 0x4008e6f7 on core 0
0x4008e6f7: _esp_error_check_failed at C:/Users/Kanimba/Desktop/esp-idf/components/esp_common/src/esp_err.c:42
Backtrace:0x4008f64b:0x3ffbc340 0x4008fe1d:0x3ffbc360 0x400951f2:0x3ffbc380 0x4008e6f7:0x3ffbc3f0 0x400d5a86:0x3ffbc410 0x401205ed:0x3ffbc430 0x40092e45:0x3ffbc450
0x4008f64b: panic_abort at C:/Users/Kanimba/Desktop/esp-idf/components/esp_system/panic.c:356
0x4008fe1d: esp_system_abort at C:/Users/Kanimba/Desktop/esp-idf/components/esp_system/system_api.c:112
0x400951f2: abort at C:/Users/Kanimba/Desktop/esp-idf/components/newlib/abort.c:46
0x4008e6f7: _esp_error_check_failed at C:/Users/Kanimba/Desktop/esp-idf/components/esp_common/src/esp_err.c:42
0x400d5a86: app_main at C:\Users\Kanimba\Desktop\work_project\esp\embedded-test-ble\build/../main/main.c:35 (discriminator 1)
0x401205ed: main_task at C:/Users/Kanimba/Desktop/esp-idf/components/freertos/port/port_common.c:133 (discriminator 2)
0x40092e45: vPortTaskWrapper at C:/Users/Kanimba/Desktop/esp-idf/components/freertos/port/xtensa/port.c:168
whereby gatt_svrs_init() is called to initializes the following;
int gatt_svrs_init(void) {
int rc;
ble_svc_gap_init();
ble_svc_gatt_init();
rc = ble_gatts_count_cfg(gatt_svsc);
if (rc != 0) {
return rc;
}
rc = ble_gatts_add_svcs(gatt_svsc);
if (rc != 0) {
return rc;
}
return 0;
}
my main,c file looks like this
#include "config.h"
#include "gatt_svr.h"
#include "esp_log.h"
#include "esp_nimble_hci.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "nvs_flash.h"
void app_main() {
int rc;
/* initalise non-valatile storage NVS*/
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
/* initialise nimble */
ESP_ERROR_CHECK(esp_nimble_hci_and_controller_init());
/* initialise apache port to nimble */
nimble_port_init();
/*Initialize the NimBLE host configuration */
ble_hs_cfg.reset_cb = ble_on_reset;
ble_hs_cfg.sync_cb = ble_on_sync;
ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb;
ble_hs_cfg.store_status_cb =
ble_store_util_status_rr; // said to not be useful, need to do more,
ESP_ERROR_CHECK(gatt_svrs_init());
// assert(rc == 0);
/*set the default device name*/
ESP_ERROR_CHECK(ble_svc_gap_device_name_set(DEVICE_NAME));
// storing configuration "quite not sure how this function works"
ble_store_config_init();
nimble_port_freertos_init(host_task);
}
and the structure of the service:
static const struct ble_gatt_svc_def gatt_svsc[] = {
{/* Device info service/ SIG */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(DEVICE_INFO_SERVICE),
.characteristics =
(struct ble_gatt_chr_def[]){
{/* manufacturer name characteristic */
.uuid = BLE_UUID16_DECLARE(MANUFACTURER_NAME),
.flags = BLE_GATT_CHR_F_READ,
.access_cb = gatt_svr_access_device_info},
{/*serial number characteristic */
.uuid = BLE_UUID16_DECLARE(DEVICE_SERIAL_NUMBER),
.flags = BLE_GATT_CHR_F_READ,
.access_cb = gatt_svr_access_device_info},
{/*software version characteristic */
.uuid = BLE_UUID16_DECLARE(SOFTWARE_VERSION),
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC,
.access_cb = gatt_svr_access_device_info},
{0}}},
{.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = &DEVICE_STATE_SERVICE.u,
.characteristics =
(struct ble_gatt_chr_def[]){{
/* manufacturer name characteristic
*/
.uuid = &CURRENT_SPECTRUM.u,
.flags = BLE_GATT_CHR_F_READ,
},
{
/* manufacturer name characteristic
*/
.uuid = &DEVICE_TEMPERATURE.u,
.flags = BLE_GATT_CHR_F_READ,
},
{
/* manufacturer name characteristic
*/
.uuid = &CURRENT_INTESITY.u,
.flags = BLE_GATT_CHR_F_READ,
},
{0}}},
{.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = &MANUAL_SERVICE.u,
.characteristics =
(struct ble_gatt_chr_def[]){{
/* manula spectrum characteristic */
.uuid = &MANUAL_SPECTRUM.u,
.flags = BLE_GATT_CHR_F_READ,
},
{
/* light intensity characteristic */
.uuid = &LIGHT_INTESITY.u,
.flags = BLE_GATT_CHR_F_READ,
},
{
/* manual power characteristic */
.uuid = &MANUAL_POWER.u,
.flags = BLE_GATT_CHR_F_READ,
},
{0}}},
{.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = &SCHEDULER_SERVICE.u,
.characteristics =
(struct ble_gatt_chr_def[]){{
/* Start_stage characteristic */
.uuid = &STAGE_START.u,
.flags = BLE_GATT_CHR_F_WRITE,
},
{
/* start day hours characteristic */
.uuid = &DAY_START_HOURS.u,
.flags = BLE_GATT_CHR_F_WRITE,
},
{
/* manufacturer name characteristic
*/
.uuid = &DAY_END_HOURS.u,
.flags = BLE_GATT_CHR_F_WRITE,
},
{
/* Light intensity characteristic */
.uuid = &LIGHT_INTESITY.u,
.flags = BLE_GATT_CHR_F_WRITE,
},
{0}}},
{0}};
I think there should be a access_cb associated for a characteristic which has a read or write flag . Can you try adding a access_cb to the characteristic with UUID SCHEDULER_SERVICE , MANUAL_SERVICE and DEVICE_STATE_SERVICE to see if it helps.
I am trying to migrate from PIC16F886 to PIC18F24K40 . NOw here I am trying to communicate PIC18F24K40 with DS1307 and Display it on 4 Segment Display. I have tested my code on PIC16F886 but not worked on PIC18F24K40 . SInce PIC18F24K40 uses MPLAB X ide and creates MCC code configuration based I2c c file and .h file . Can someone suggest what wrong done i have done in below code
I could not able to update time once written.
/**
Generated Main Source File
Company:
Microchip Technology Inc.
File Name:
main.c
Summary:
This is the main file generated using MPLAB(c) Code Configurator
Description:
This header file provides implementations for driver APIs for all modules selected in the GUI.
Generation Information :
Product Revision : MPLAB(c) Code Configurator - 4.15
Device : PIC18F24K40
Driver Version : 2.00
The generated drivers are tested against the following:
Compiler : XC8 1.35
MPLAB : MPLAB X 3.40
*/
/*
(c) 2016 Microchip Technology Inc. and its subsidiaries. You may use this
software and any derivatives exclusively with Microchip products.
THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
PARTICULAR PURPOSE, OR ITS INTERACTION WITH MICROCHIP PRODUCTS, COMBINATION
WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION.
IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE OF THESE
TERMS.
*/
#include "mcc_generated_files/mcc.h"
#include "mcc_generated_files/i2c1.h"
uint8_t status;
#define DS1307_RETRY_MAX 100 // define the retry count
#define Ds1307_ADDRESS 0xD0 // slave device address
#define RTC_addres 0x68 // RTC slave device address
//static unsigned char readI2C[10], writeI2C[4];
#define buffersize 20
static unsigned char writeBuffer[buffersize]; //Buffer for I2C writing.
static unsigned char readbuffer[buffersize]; // Buffer for I2C reading.
uint8_t second;
uint8_t start_addres;
uint8_t length;
//I2C1_MESSAGE_STATUS w_status;
uint8_t sourceData[] = {0x1A, 0x2A, 0x4A, 0x8A,0x1A, 0x2A, 0x4A, 0x8A,0x1A, 0x2A, 0x4A, 0x8A,0x1A, 0x2A, 0x4A, 0x8A};
uint8_t addressBuffer[] = {0xAB,0x10} ; //Put your address here
uint8_t readBuffer[16];
uint8_t readByte;
# define LED RC7
unsigned int i;
unsigned int count;
unsigned int x;
unsigned short sec;
unsigned short min;
unsigned short hour;
unsigned short date;
unsigned short month;
unsigned short year;
unsigned short day;
unsigned short int temp=0;
unsigned short r_data;
#define Seg1 0x01
#define Seg2 0x02
#define Seg3 0x04
#define Seg4 0x08
#define Seg5 0x10
#define Seg6 0x20
unsigned short int cnt, num,Dgt=0;;
unsigned short int temp1,temp2,temp3;
void Delay(int k)
{
for(i=0;i<=k;i++);
}
void Blink_LED()
{
LED=!LED;
Delay(10000);
}
void SetSeg(unsigned short data, unsigned short segno)
{
switch(data)
{
case 0: PORTB = 0x3F; break;
case 1: PORTB = 0x06; break;
case 2: PORTB = 0x5B; break;
case 3: PORTB = 0x4F; break;
case 4: PORTB = 0x66; break;
case 5: PORTB = 0x6D; break;
case 6: PORTB = 0x7D; break;
case 7: PORTB = 0x07; break;
case 8: PORTB = 0x7F; break;
case 9: PORTB = 0x6F; break;
default : PORTB = 0X00; break;
}
if(segno==1)
{
PORTA = Seg4;
}
if(segno==2)
{
PORTA = Seg3;
}
if(segno==3)
{
PORTA = Seg2;
}
if(segno==4)
{
PORTA = Seg1;
}
}
unsigned int bcdtodecimal(unsigned int bcd)
{
unsigned int decimal;
decimal = (((bcd & 0xF0) >> 4) * 10) + (bcd & 0x0F);
return decimal;
}
void wait_mssp(void)
{
while(!PIR3bits.SSP1IF);
PIR3bits.SSP1IF =0;
}
void ds1307_write(unsigned char addr ,unsigned char data)
{
SSP1CON2bits.SEN =1; //Start bit
//SSP1BUF = 0XD0; //slave address(address of ds1307) + write bit
SSP1BUF =0X68;
SSP1BUF =addr;
SSP1BUF = data;
SSP1CON2bits.PEN =1; //stop bit
}
unsigned int ds1307_read(unsigned char addr)
{
SSP1CON2bits.RSEN =1;
//SSP1BUF =0XD0; //slave address(address of ds1307) + write bit;
SSP1BUF =0X68;
SSP1BUF =addr;
SSP1CON2bits.RSEN =1;
//SSP1BUF =0XD1; //slave address(address of ds1307) + read bit;
SSP1BUF =0X69;
SSP1CON2bits.RCEN =1;
SSP1CON2bits.ACKDT=1;
SSP1CON2bits.ACKEN =1;
SSP1CON2bits.PEN=1;
x = SSP1BUF;
return (x);
}
void SetDateTime()
{
ds1307_write(0X00,0x03);
ds1307_write(0X01,0X07);
ds1307_write(0X02,0X00);
ds1307_write(0X3,0X01);
ds1307_write(0X04,0x07);
ds1307_write(0X5,0X08);
ds1307_write(0X6,0X08);
}
void GetDateTime()
{
sec = ds1307_read(0X00);
sec=bcdtodecimal(sec);
min = ds1307_read(0X01);
min = bcdtodecimal(min);
hour = ds1307_read(0X02);
hour=bcdtodecimal( hour);
day= ds1307_read(0X03);
day = bcdtodecimal(day);
date= ds1307_read(0X04);
date=bcdtodecimal(date);
month= ds1307_read(0X05);
month = bcdtodecimal( month);
year= ds1307_read(0X06);
year= bcdtodecimal(year);
}
void Blink_Count()
{
if(PIR0bits.TMR0IF == 1)
{
PIR0bits.TMR0IF =0;
count=count+1;
if(count>=15)
{
LED=!LED;
count=0;
// SetSeg(min/10,4);
// SetSeg(min%10,3);
// SetSeg(sec/ 10,2);
// SetSeg(sec%10,1);
}
}
}
void main(void)
{
// Initialize the device
SYSTEM_Initialize();
// If using interrupts in PIC18 High/Low Priority Mode you need to enable the Global High and Low Interrupts
// If using interrupts in PIC Mid-Range Compatibility Mode you need to enable the Global and Peripheral Interrupts
// Use the following macros to:
// Enable high priority global interrupts
//INTERRUPT_GlobalInterruptHighEnable();
// Enable low priority global interrupts.
//INTERRUPT_GlobalInterruptLowEnable();
// Disable high priority global interrupts
//INTERRUPT_GlobalInterruptHighDisable();
// Disable low priority global interrupts.
//INTERRUPT_GlobalInterruptLowDisable();
// Enable the Global Interrupts
//INTERRUPT_GlobalInterruptEnable();
// Enable the Peripheral Interrupts
//INTERRUPT_PeripheralInterruptEnable();
// Disable the Global Interrupts
//INTERRUPT_GlobalInterruptDisable();
// Disable the Peripheral Interrupts
//INTERRUPT_PeripheralInterruptDisable();
// I2C1_Initialize();
SSP1CLKPPS = 0x0E; //RB6->MSSP:SCL;
SSP1DATPPS = 0x0C; //RB4->MSSP:SDA;
RB6PPS = 0x10; //RB6->MSSP:SCL;
RB4PPS = 0x11; //RB4->MSSP:SDA;
SetDateTime();
while (1)
{
GetDateTime();
SetSeg(min/10,4);
SetSeg(min%10,3);
SetSeg(sec/ 10,2);
SetSeg(sec%10,1);
}
}
Based On MCC code configuration and used library below. But i could not see sec parameter updating after writing.
void main(void)
{
uint8_t second;
uint8_t start_addres;
uint8_t length;
I2C1_MESSAGE_STATUS w_status;
I2C1_MESSAGE_STATUS r_status;
// Initialize the device
SYSTEM_Initialize();
start_addres = 0;
length =12;
I2C1_MasterWriteTRBBuild( 0X00, length, RTC_addres, &w_status);
while (1)
{
I2C1_MasterReadTRBBuild( &second, length, RTC_addres, &r_status);
I2C1_MasterRead(&second, length, RTC_addres, &r_status);
sec=second;
}
}
THis is I2C1.c file created after MCC
typedef union
{
struct
{
uint8_t full:1;
uint8_t empty:1;
uint8_t reserved:6;
}s;
uint8_t status;
}I2C_TR_QUEUE_STATUS;
/**
I2C Driver Queue Entry Type
#Summary
Defines the object used for an entry in the i2c queue items.
#Description
This defines the object in the i2c queue. Each entry is a composed
of a list of TRBs, the number of the TRBs and the status of the
currently processed TRB.
*/
typedef struct
{
uint8_t count; // a count of trb's in the trb list
I2C1_TRANSACTION_REQUEST_BLOCK *ptrb_list; // pointer to the trb list
I2C1_MESSAGE_STATUS *pTrFlag; // set with the error of the last trb sent.
// if all trb's are sent successfully,
// then this is I2C1_MESSAGE_COMPLETE
} I2C_TR_QUEUE_ENTRY;
/**
I2C Master Driver Object Type
#Summary
Defines the object that manages the i2c master.
#Description
This defines the object that manages the sending and receiving of
i2c master transactions.
*/
typedef struct
{
/* Read/Write Queue */
I2C_TR_QUEUE_ENTRY *pTrTail; // tail of the queue
I2C_TR_QUEUE_ENTRY *pTrHead; // head of the queue
I2C_TR_QUEUE_STATUS trStatus; // status of the last transaction
uint8_t i2cDoneFlag; // flag to indicate the current
// transaction is done
uint8_t i2cErrors; // keeps track of errors
} I2C_OBJECT ;
/**
I2C Master Driver State Enumeration
#Summary
Defines the different states of the i2c master.
#Description
This defines the different states that the i2c master
used to process transactions on the i2c bus.
*/
typedef enum
{
S_MASTER_IDLE,
S_MASTER_RESTART,
S_MASTER_SEND_ADDR,
S_MASTER_SEND_DATA,
S_MASTER_SEND_STOP,
S_MASTER_ACK_ADDR,
S_MASTER_RCV_DATA,
S_MASTER_RCV_STOP,
S_MASTER_ACK_RCV_DATA,
S_MASTER_NOACK_STOP,
S_MASTER_SEND_ADDR_10BIT_LSB,
S_MASTER_10BIT_RESTART,
} I2C_MASTER_STATES;
/**
Section: Macro Definitions
*/
/* defined for I2C1 */
#ifndef I2C1_CONFIG_TR_QUEUE_LENGTH
#define I2C1_CONFIG_TR_QUEUE_LENGTH 1
#endif
#define I2C1_TRANSMIT_REG SSP1BUF // Defines the transmit register used to send data.
#define I2C1_RECEIVE_REG SSP1BUF // Defines the receive register used to receive data.
// The following control bits are used in the I2C state machine to manage
// the I2C module and determine next states.
#define I2C1_WRITE_COLLISION_STATUS_BIT SSP1CON1bits.WCOL // Defines the write collision status bit.
#define I2C1_MODE_SELECT_BITS SSP1CON1bits.SSPM // I2C Master Mode control bit.
#define I2C1_MASTER_ENABLE_CONTROL_BITS SSP1CON1bits.SSPEN // I2C port enable control bit.
#define I2C1_START_CONDITION_ENABLE_BIT SSP1CON2bits.SEN // I2C START control bit.
#define I2C1_REPEAT_START_CONDITION_ENABLE_BIT SSP1CON2bits.RSEN // I2C Repeated START control bit.
#define I2C1_RECEIVE_ENABLE_BIT SSP1CON2bits.RCEN // I2C Receive enable control bit.
#define I2C1_STOP_CONDITION_ENABLE_BIT SSP1CON2bits.PEN // I2C STOP control bit.
#define I2C1_ACKNOWLEDGE_ENABLE_BIT SSP1CON2bits.ACKEN // I2C ACK start control bit.
#define I2C1_ACKNOWLEDGE_DATA_BIT SSP1CON2bits.ACKDT // I2C ACK data control bit.
#define I2C1_ACKNOWLEDGE_STATUS_BIT SSP1CON2bits.ACKSTAT // I2C ACK status bit.
#define I2C1_7bit true
/**
Section: Local Functions
*/
void I2C1_FunctionComplete(void);
void I2C1_Stop(I2C1_MESSAGE_STATUS completion_code);
/**
Section: Local Variables
*/
static I2C_TR_QUEUE_ENTRY i2c1_tr_queue[I2C1_CONFIG_TR_QUEUE_LENGTH];
static I2C_OBJECT i2c1_object;
static I2C_MASTER_STATES i2c1_state = S_MASTER_IDLE;
static uint8_t i2c1_trb_count = 0;
static I2C1_TRANSACTION_REQUEST_BLOCK *p_i2c1_trb_current = NULL;
static I2C_TR_QUEUE_ENTRY *p_i2c1_current = NULL;
/**
Section: Driver Interface
*/
void I2C1_Initialize(void)
{
i2c1_object.pTrHead = i2c1_tr_queue;
i2c1_object.pTrTail = i2c1_tr_queue;
i2c1_object.trStatus.s.empty = true;
i2c1_object.trStatus.s.full = false;
i2c1_object.i2cErrors = 0;
// SMP Standard Speed; CKE enabled;
SSP1STAT = 0xC0;
// SSPEN enabled; CKP disabled; SSPM FOSC/4_SSPxADD_I2C;
SSP1CON1 = 0x28;
// SBCDE disabled; BOEN disabled; SCIE disabled; PCIE disabled; DHEN disabled; SDAHT 100ns; AHEN disabled;
SSP1CON3 = 0x00;
// Baud Rate Generator Value: SSPADD 2;
SSP1ADD = 0x02;
// clear the master interrupt flag
PIR3bits.SSP1IF = 0;
// enable the master interrupt
PIE3bits.SSP1IE = 1;
}
uint8_t I2C1_ErrorCountGet(void)
{
uint8_t ret;
ret = i2c1_object.i2cErrors;
return ret;
}
void I2C1_ISR ( void )
{
static uint8_t *pi2c_buf_ptr;
static uint16_t i2c_address = 0;
static uint8_t i2c_bytes_left = 0;
static uint8_t i2c_10bit_address_restart = 0;
PIR3bits.SSP1IF = 0;
// Check first if there was a collision.
// If we have a Write Collision, reset and go to idle state */
if(I2C1_WRITE_COLLISION_STATUS_BIT)
{
// clear the Write colision
I2C1_WRITE_COLLISION_STATUS_BIT = 0;
i2c1_state = S_MASTER_IDLE;
*(p_i2c1_current->pTrFlag) = I2C1_MESSAGE_FAIL;
// reset the buffer pointer
p_i2c1_current = NULL;
return;
}
/* Handle the correct i2c state */
switch(i2c1_state)
{
case S_MASTER_IDLE: /* In reset state, waiting for data to send */
if(i2c1_object.trStatus.s.empty != true)
{
// grab the item pointed by the head
p_i2c1_current = i2c1_object.pTrHead;
i2c1_trb_count = i2c1_object.pTrHead->count;
p_i2c1_trb_current = i2c1_object.pTrHead->ptrb_list;
i2c1_object.pTrHead++;
// check if the end of the array is reached
if(i2c1_object.pTrHead == (i2c1_tr_queue + I2C1_CONFIG_TR_QUEUE_LENGTH))
{
// adjust to restart at the beginning of the array
i2c1_object.pTrHead = i2c1_tr_queue;
}
// since we moved one item to be processed, we know
// it is not full, so set the full status to false
i2c1_object.trStatus.s.full = false;
// check if the queue is empty
if(i2c1_object.pTrHead == i2c1_object.pTrTail)
{
// it is empty so set the empty status to true
i2c1_object.trStatus.s.empty = true;
}
// send the start condition
I2C1_START_CONDITION_ENABLE_BIT = 1;
// start the i2c request
i2c1_state = S_MASTER_SEND_ADDR;
}
break;
case S_MASTER_RESTART:
/* check for pending i2c Request */
// ... trigger a REPEATED START
I2C1_REPEAT_START_CONDITION_ENABLE_BIT = 1;
// start the i2c request
i2c1_state = S_MASTER_SEND_ADDR;
break;
case S_MASTER_SEND_ADDR_10BIT_LSB:
if(I2C1_ACKNOWLEDGE_STATUS_BIT)
{
i2c1_object.i2cErrors++;
I2C1_Stop(I2C1_MESSAGE_ADDRESS_NO_ACK);
}
else
{
// Remove bit 0 as R/W is never sent here
I2C1_TRANSMIT_REG = (i2c_address >> 1) & 0x00FF;
// determine the next state, check R/W
if(i2c_address & 0x01)
{
// if this is a read we must repeat start
// the bus to perform a read
i2c1_state = S_MASTER_10BIT_RESTART;
}
else
{
// this is a write continue writing data
i2c1_state = S_MASTER_SEND_DATA;
}
}
break;
case S_MASTER_10BIT_RESTART:
if(I2C1_ACKNOWLEDGE_STATUS_BIT)
{
i2c1_object.i2cErrors++;
I2C1_Stop(I2C1_MESSAGE_ADDRESS_NO_ACK);
}
else
{
// ACK Status is good
// restart the bus
I2C1_REPEAT_START_CONDITION_ENABLE_BIT = 1;
// fudge the address so S_MASTER_SEND_ADDR works correctly
// we only do this on a 10-bit address resend
i2c_address = 0x00F0 | ((i2c_address >> 8) & 0x0006);
// set the R/W flag
i2c_address |= 0x0001;
// set the address restart flag so we do not change the address
i2c_10bit_address_restart = 1;
// Resend the address as a read
i2c1_state = S_MASTER_SEND_ADDR;
}
break;
case S_MASTER_SEND_ADDR:
/* Start has been sent, send the address byte */
/* Note:
On a 10-bit address resend (done only during a 10-bit
device read), the original i2c_address was modified in
S_MASTER_10BIT_RESTART state. So the check if this is
a 10-bit address will fail and a normal 7-bit address
is sent with the R/W bit set to read. The flag
i2c_10bit_address_restart prevents the address to
be re-written.
*/
if(i2c_10bit_address_restart != 1)
{
// extract the information for this message
i2c_address = p_i2c1_trb_current->address;
pi2c_buf_ptr = p_i2c1_trb_current->pbuffer;
i2c_bytes_left = p_i2c1_trb_current->length;
}
// check for 10-bit address
if(!I2C1_7bit && (0x0 != i2c_address))
{
if (0 == i2c_10bit_address_restart)
{
// we have a 10 bit address
// send bits<9:8>
// mask bit 0 as this is always a write
I2C1_TRANSMIT_REG = 0xF0 | ((i2c_address >> 8) & 0x0006);
i2c1_state = S_MASTER_SEND_ADDR_10BIT_LSB;
}
else
{
// resending address bits<9:8> to trigger read
I2C1_TRANSMIT_REG = i2c_address;
i2c1_state = S_MASTER_ACK_ADDR;
// reset the flag so the next access is ok
i2c_10bit_address_restart = 0;
}
}
else
{
// Transmit the address
I2C1_TRANSMIT_REG = i2c_address;
if(i2c_address & 0x01)
{
// Next state is to wait for address to be acked
i2c1_state = S_MASTER_ACK_ADDR;
}
else
{
// Next state is transmit
i2c1_state = S_MASTER_SEND_DATA;
}
}
break;
case S_MASTER_SEND_DATA:
// Make sure the previous byte was acknowledged
if(I2C1_ACKNOWLEDGE_STATUS_BIT)
{
// Transmission was not acknowledged
i2c1_object.i2cErrors++;
// Reset the Ack flag
I2C1_ACKNOWLEDGE_STATUS_BIT = 0;
// Send a stop flag and go back to idle
I2C1_Stop(I2C1_DATA_NO_ACK);
}
else
{
// Did we send them all ?
if(i2c_bytes_left-- == 0U)
{
// yup sent them all!
// update the trb pointer
p_i2c1_trb_current++;
// are we done with this string of requests?
if(--i2c1_trb_count == 0)
{
I2C1_Stop(I2C1_MESSAGE_COMPLETE);
}
else
{
// no!, there are more TRB to be sent.
//I2C1_START_CONDITION_ENABLE_BIT = 1;
// In some cases, the slave may require
// a restart instead of a start. So use this one
// instead.
I2C1_REPEAT_START_CONDITION_ENABLE_BIT = 1;
// start the i2c request
i2c1_state = S_MASTER_SEND_ADDR;
}
}
else
{
// Grab the next data to transmit
I2C1_TRANSMIT_REG = *pi2c_buf_ptr++;
}
}
break;
case S_MASTER_ACK_ADDR:
/* Make sure the previous byte was acknowledged */
if(I2C1_ACKNOWLEDGE_STATUS_BIT)
{
// Transmission was not acknowledged
i2c1_object.i2cErrors++;
// Send a stop flag and go back to idle
I2C1_Stop(I2C1_MESSAGE_ADDRESS_NO_ACK);
// Reset the Ack flag
I2C1_ACKNOWLEDGE_STATUS_BIT = 0;
}
else
{
I2C1_RECEIVE_ENABLE_BIT = 1;
i2c1_state = S_MASTER_ACK_RCV_DATA;
}
break;
case S_MASTER_RCV_DATA:
/* Acknowledge is completed. Time for more data */
// Next thing is to ack the data
i2c1_state = S_MASTER_ACK_RCV_DATA;
// Set up to receive a byte of data
I2C1_RECEIVE_ENABLE_BIT = 1;
break;
case S_MASTER_ACK_RCV_DATA:
// Grab the byte of data received and acknowledge it
*pi2c_buf_ptr++ = I2C1_RECEIVE_REG;
// Check if we received them all?
if(--i2c_bytes_left)
{
/* No, there's more to receive */
// No, bit 7 is clear. Data is ok
// Set the flag to acknowledge the data
I2C1_ACKNOWLEDGE_DATA_BIT = 0;
// Wait for the acknowledge to complete, then get more
i2c1_state = S_MASTER_RCV_DATA;
}
else
{
// Yes, it's the last byte. Don't ack it
// Flag that we will nak the data
I2C1_ACKNOWLEDGE_DATA_BIT = 1;
I2C1_FunctionComplete();
}
// Initiate the acknowledge
I2C1_ACKNOWLEDGE_ENABLE_BIT = 1;
break;
case S_MASTER_RCV_STOP:
case S_MASTER_SEND_STOP:
// Send the stop flag
I2C1_Stop(I2C1_MESSAGE_COMPLETE);
break;
default:
// This case should not happen, if it does then
// terminate the transfer
i2c1_object.i2cErrors++;
I2C1_Stop(I2C1_LOST_STATE);
break;
}
}
void I2C1_FunctionComplete(void)
{
// update the trb pointer
p_i2c1_trb_current++;
// are we done with this string of requests?
if(--i2c1_trb_count == 0)
{
i2c1_state = S_MASTER_SEND_STOP;
}
else
{
i2c1_state = S_MASTER_RESTART;
}
}
void I2C1_Stop(I2C1_MESSAGE_STATUS completion_code)
{
// then send a stop
I2C1_STOP_CONDITION_ENABLE_BIT = 1;
// make sure the flag pointer is not NULL
if (p_i2c1_current->pTrFlag != NULL)
{
// update the flag with the completion code
*(p_i2c1_current->pTrFlag) = completion_code;
}
// Done, back to idle
i2c1_state = S_MASTER_IDLE;
}
void I2C1_MasterWrite(
uint8_t *pdata,
uint8_t length,
uint16_t address,
I2C1_MESSAGE_STATUS *pflag)
{
static I2C1_TRANSACTION_REQUEST_BLOCK trBlock;
// check if there is space in the queue
if (i2c1_object.trStatus.s.full != true)
{
I2C1_MasterWriteTRBBuild(&trBlock, pdata, length, address);
I2C1_MasterTRBInsert(1, &trBlock, pflag);
}
else
{
*pflag = I2C1_MESSAGE_FAIL;
}
}
void I2C1_MasterRead(
uint8_t *pdata,
uint8_t length,
uint16_t address,
I2C1_MESSAGE_STATUS *pflag)
{
static I2C1_TRANSACTION_REQUEST_BLOCK trBlock;
// check if there is space in the queue
if (i2c1_object.trStatus.s.full != true)
{
I2C1_MasterReadTRBBuild(&trBlock, pdata, length, address);
I2C1_MasterTRBInsert(1, &trBlock, pflag);
}
else
{
*pflag = I2C1_MESSAGE_FAIL;
}
}
void I2C1_MasterTRBInsert(
uint8_t count,
I2C1_TRANSACTION_REQUEST_BLOCK *ptrb_list,
I2C1_MESSAGE_STATUS *pflag)
{
// check if there is space in the queue
if (i2c1_object.trStatus.s.full != true)
{
*pflag = I2C1_MESSAGE_PENDING;
i2c1_object.pTrTail->ptrb_list = ptrb_list;
i2c1_object.pTrTail->count = count;
i2c1_object.pTrTail->pTrFlag = pflag;
i2c1_object.pTrTail++;
// check if the end of the array is reached
if (i2c1_object.pTrTail == (i2c1_tr_queue + I2C1_CONFIG_TR_QUEUE_LENGTH))
{
// adjust to restart at the beginning of the array
i2c1_object.pTrTail = i2c1_tr_queue;
}
// since we added one item to be processed, we know
// it is not empty, so set the empty status to false
i2c1_object.trStatus.s.empty = false;
// check if full
if (i2c1_object.pTrHead == i2c1_object.pTrTail)
{
// it is full, set the full status to true
i2c1_object.trStatus.s.full = true;
}
}
else
{
*pflag = I2C1_MESSAGE_FAIL;
}
// for interrupt based
if (*pflag == I2C1_MESSAGE_PENDING)
{
while(i2c1_state != S_MASTER_IDLE);
{
// force the task to run since we know that the queue has
// something that needs to be sent
PIR3bits.SSP1IF = true;
}
} // block until request is complete
}
void I2C1_MasterReadTRBBuild(
I2C1_TRANSACTION_REQUEST_BLOCK *ptrb,
uint8_t *pdata,
uint8_t length,
uint16_t address)
{
ptrb->address = address << 1;
// make this a read
ptrb->address |= 0x01;
ptrb->length = length;
ptrb->pbuffer = pdata;
}
void I2C1_MasterWriteTRBBuild(
I2C1_TRANSACTION_REQUEST_BLOCK *ptrb,
uint8_t *pdata,
uint8_t length,
uint16_t address)
{
ptrb->address = address << 1;
ptrb->length = length;
ptrb->pbuffer = pdata;
}
bool I2C1_MasterQueueIsEmpty(void)
{
return(i2c1_object.trStatus.s.empty);
}
bool I2C1_MasterQueueIsFull(void)
{
return(i2c1_object.trStatus.s.full);
}
void I2C1_BusCollisionISR( void )
{
// enter bus collision handling code here
}
/**
End of File
*/
I have two threads, one calls WriteFile, the other calls ReadFile, both uses the same serial port at 115200. What I have found repeatedly is that when I add more sequential WriteFile calls in the writing thread, is that I have an increased number of check-sum failures i.e. corrupt data. If I add delays between the WriteFile calls in the writing thread (using CBaseDLIMessage::CrossSleep(20) ), the check-sum errors reduce or even completely go away (depending on the sleep time), however the problem comes back when adding additional WriteFile methods.
Is it possible that the WriteFile method can somehow write data into a shared buffer, which is also used for reading (at driver level), which subsequently corrupts my read data?
My serial setup code looks like this:
CommHandle OpenSerialPort(int nId, long baud)
{
#if defined(USE_WINDOWS_SERIAL_PORT_LIB)
char szCOM[16];
/* COM waiting */
COMMTIMEOUTS g_cto =
{
MAXDWORD, /* ReadIntervalTimeOut */
0, /* ReadTotalTimeOutMultiplier */
0, /* ReadTotalTimeOutConstant */
0, /* WriteTotalTimeOutMultiplier */
0 /* WriteTotalTimeOutConstant */
};
/* COM configuration */
DCB g_dcb =
{
sizeof(DCB), /* DCBlength */
baud, /* BaudRate */
TRUE, /* fBinary */
FALSE, /* fParity */
FALSE, /* fOutxCtsFlow */
FALSE, /* fOutxDsrFlow */
DTR_CONTROL_DISABLE, /* fDtrControl */
FALSE, /* fDsrSensitivity */
FALSE, /* fTXContinueOnXoff */
FALSE, /* fOutX */
FALSE, /* fInX */
FALSE, /* fErrorChar */
FALSE, /* fNull */
RTS_CONTROL_DISABLE, /* fRtsControl */
FALSE, /* fAbortOnError */
0, /* fDummy2 */
0, /* wReserved */
0x100, /* XonLim */
0x100, /* XoffLim */
8, /* ByteSize */
NOPARITY, /* Parity */
ONESTOPBIT, /* StopBits */
0x11, /* XonChar */
0x13, /* XoffChar */
'?', /* ErrorChar */
0x1A, /* EofChar */
0x10 /* EvtChar */
};
//cout << "COM:::" << nId;
sprintf(szCOM, "\\\\.\\COM%d", nId);
HANDLE hCOM = CreateFile(szCOM, /* lpFileName */
GENERIC_READ|GENERIC_WRITE, /* dwDesiredAccess */
0, /* dwShareMode */
NULL, /* lpSecurityAttributes */
OPEN_EXISTING, /* dwCreationDisposition */
FILE_ATTRIBUTE_SYSTEM, /* dwFlagsAndAttributes */
NULL); /* hTemplateFile */
//std::cout << "COM: " << (int)nId << "\n";
if(hCOM == INVALID_HANDLE_VALUE)
{
//std::cout << "INVALID_HANDLE_VALUE \n" ;
DWORD err = GetLastError();
if (err == ERROR_FILE_NOT_FOUND)
{
std::cout << "Error: Failed to open COM[" << nId << "]\n";
}
else if(err == ERROR_INVALID_NAME)
{
std::cout << "\nError: \n%s 'filename, directory name, or volume label syntax is incorrect'\n"; //error code 0x7B
}
else
{
//cout << "\nHandle creation error code: %x\n" << err;
}
return 0;
}
else
{
std::cout << "COM[" << nId << "] OPEN. Baud: " << baud <<"\n";
}
// COM buffer size
SetupComm(hCOM, RX_SIZE, TX_SIZE);
// COM config
if(!SetCommTimeouts(hCOM, &g_cto) || !SetCommState(hCOM, &g_dcb))
{
CloseHandle(hCOM);
return 0;
}
// COM buffer purge
PurgeComm(hCOM, PURGE_TXCLEAR|PURGE_RXCLEAR|PURGE_TXABORT|PURGE_RXABORT);
EscapeCommFunction(hCOM, SETDTR);
return hCOM;
#else
wxSerialPort *pwxSerialPort = new wxSerialPort();
char szPort[32];
sprintf(szPort,"com%d", nId);
if(pwxSerialPort->Open(szPort) < 0) {
return 0;
}
// set the baudrate
pwxSerialPort->SetBaudRate((wxBaud)baud);
return pwxSerialPort;
#endif
}
int CloseSerialPort(CommHandle hSerialPort)
{
#if defined(USE_WINDOWS_SERIAL_PORT_LIB)
CloseHandle(hSerialPort);
return 1;
#else
hSerialPort->Close();
delete hSerialPort;
return 1;
#endif
}
int WriteDataToSerialPort(CommHandle hSerialPort, void *pMsg, unsigned short messageLength, unsigned int *pBytesWritten)
{
*pBytesWritten = 0;
if(hSerialPort == 0)
{
//cout << "hSerialPort ====== 0";
return -1;
}
#if defined(USE_WINDOWS_SERIAL_PORT_LIB)
return WriteFile(hSerialPort, (char*)pMsg, messageLength, (DWORD*)pBytesWritten, NULL);
#else
*pBytesWritten = hSerialPort->Write((char*)pMsg, messageLength);
return 1;
#endif
}
int ReadDataFromSerialPort(CommHandle hSerialPort, void *pMsg, unsigned short messageLength, unsigned int *pBytesRead)
{
unsigned short i;
*pBytesRead = 0;
i = 0;
if(hSerialPort == 0)
{
return -1;
}
#if defined(USE_WINDOWS_SERIAL_PORT_LIB)
return ReadFile(hSerialPort, (char*)pMsg, messageLength, (DWORD*)pBytesRead, NULL);
#else
*pBytesRead = hSerialPort->Read((char*)pMsg, messageLength);
return 1;
#endif
}
Communication through serial port is slow.
You should use WriteFileEx instead of WriteFile.
You can specify a routine which may execute when the writting(transmitting) is completed or failed.
If you write next data after that routine has been executed, overflow of data may not be occured.