DS1339 RTC

embedded_systems
Posts: 10
Joined: Tue May 09, 2017 6:42 pm

DS1339 RTC

Postby embedded_systems » Tue May 09, 2017 7:14 pm

I am working with the DS1339 RTC, and I am having a few issues. I watched Kolbans video on the DS1307. Both the DS1339 and DS1307 are from the same manufacture. I'm using the DS1339 because I needed a SMT component. Below I have my code. It is very similar to Kolbans example. I only added the app_main() and changed the SDA and SCL values to match my configuration. I also hooked it up to a raspberry pi, and I detected the RTC on address 0x68. My other i2c devices are working when I do not enable this code.

Code: Select all

#include <apps/sntp/sntp.h>
#include <driver/i2c.h>
#include <esp_log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <lwip/sockets.h>
#include <stdio.h>
#include <time.h>

#include "sdkconfig.h"

#define SDA_PIN 4
#define SCL_PIN 5
#define DS1307_ADDRESS 0x68

static char tag[] = "ds1307";

static uint8_t intToBCD(uint8_t num) {
	return ((num / 10) << 4) | (num%10);
}

static uint8_t bcdToInt(uint8_t bcd) {
	// 0x10
	return ((bcd >> 4) * 10) + (bcd & 0x0f);;
}

static void startSNTP() {
	ip_addr_t addr;
	sntp_setoperatingmode(SNTP_OPMODE_POLL);
	inet_pton(AF_INET, "129.6.15.28", &addr);
	sntp_setserver(0, &addr);
	sntp_init();
}


static void initI2C() {
	i2c_config_t conf;
	conf.mode = I2C_MODE_MASTER;
	conf.sda_io_num = SDA_PIN;
	conf.scl_io_num = SCL_PIN;
	conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
	conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
	conf.master.clk_speed = 100000;
	ESP_ERROR_CHECK(i2c_param_config(I2C_NUM_0, &conf));
	ESP_ERROR_CHECK(i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0));
}

/*
 * The value read from the DS1307 is 7 bytes encoded in BCD:
 * 0 - Seconds - 00-59
 * 1 - Minutes - 00-59
 * 2 - Hours   - 00-23
 * 3 - Day     - 01-07
 * 4 - Date    - 01-31
 * 5 - Month   - 01-12
 * 6 - Year    - 00-99
 *
 */
time_t readValue() {
	i2c_cmd_handle_t cmd = i2c_cmd_link_create();
	ESP_ERROR_CHECK(i2c_master_start(cmd));
	ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (DS1307_ADDRESS << 1) | I2C_MASTER_WRITE, 1 /* expect ack */));
	ESP_ERROR_CHECK(i2c_master_write_byte(cmd, 0x0, 1));
	ESP_ERROR_CHECK(i2c_master_start(cmd));
	ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (DS1307_ADDRESS << 1) | I2C_MASTER_READ, 1 /* expect ack */));
	uint8_t data[7];
	ESP_ERROR_CHECK(i2c_master_read(cmd, data, 7, 0));
	ESP_ERROR_CHECK(i2c_master_stop(cmd));
	esp_err_t errRc;
	errRc = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000/portTICK_PERIOD_MS);
		if (errRc != 0) {
			ESP_LOGE(tag, "i2c_master_cmd_begin: %d", errRc);
		}
	i2c_cmd_link_delete(cmd);

	int i;
	for (i=0; i<7; i++) {
		ESP_LOGD(tag, "%d: 0x%.2x", i, data[i]);
	}

	struct tm tm;
	tm.tm_sec  = bcdToInt(data[0]);
	tm.tm_min  = bcdToInt(data[1]);
	tm.tm_hour = bcdToInt(data[2]);
	tm.tm_mday = bcdToInt(data[4]);
	tm.tm_mon  = bcdToInt(data[5]) - 1; // 0-11 - Note: The month on the DS1307 is 1-12.
	tm.tm_year = bcdToInt(data[6]) + 100; // Years since 1900
	time_t readTime = mktime(&tm);
	return readTime;
}

void writeValue(time_t newTime) {
	ESP_LOGD(tag, ">> writeValue: %ld", newTime);
	struct tm tm;
	gmtime_r(&newTime, &tm);
	char buf[30];
	ESP_LOGD(tag, " - %s", asctime_r(&tm, buf));

	esp_err_t errRc;
	i2c_cmd_handle_t cmd = i2c_cmd_link_create();
	ESP_ERROR_CHECK(i2c_master_start(cmd));
	ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (DS1307_ADDRESS << 1) | I2C_MASTER_WRITE, 1 /* expect ack */));
	ESP_ERROR_CHECK(i2c_master_write_byte(cmd, 0x0, 1));
	ESP_ERROR_CHECK(i2c_master_write_byte(cmd, intToBCD(tm.tm_sec), 1));      // seconds
	ESP_ERROR_CHECK(i2c_master_write_byte(cmd, intToBCD(tm.tm_min), 1 ));     // minutes
	ESP_ERROR_CHECK(i2c_master_write_byte(cmd, intToBCD(tm.tm_hour), 1 ));    // hours
	ESP_ERROR_CHECK(i2c_master_write_byte(cmd, intToBCD(tm.tm_wday+1), 1 ));  // week day
	ESP_ERROR_CHECK(i2c_master_write_byte(cmd, intToBCD(tm.tm_mday), 1));     // date of month
	ESP_ERROR_CHECK(i2c_master_write_byte(cmd, intToBCD(tm.tm_mon+1), 1));    // month
	ESP_ERROR_CHECK(i2c_master_write_byte(cmd, intToBCD(tm.tm_year-100), 1)); // year
	ESP_ERROR_CHECK(i2c_master_stop(cmd));
	errRc = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000/portTICK_PERIOD_MS);
	if (errRc != 0) {
		ESP_LOGE(tag, "i2c_master_cmd_begin: %d", errRc);
	}
	i2c_cmd_link_delete(cmd);
}

void task_ds1307(void *ignore) {
//	int doWrite = 1;
	ESP_LOGD(tag, ">> ds1307");
	initI2C();
//	if (doWrite) {
//		startSNTP();
//		time_t t;
//		while(time(&t) < 1000) {
//			ESP_LOGD(tag, "Waiting for SNTP ...");
//			vTaskDelay(1000/portTICK_PERIOD_MS);
//		}
		writeValue(1494356422);
//	}

	while(1) {
		time_t t = time(NULL);
		ESP_LOGD(tag, "time: %ld", t);
		t = readValue();
		ESP_LOGD(tag, "Read from DS1307: %ld", t);
		vTaskDelay(1000/portTICK_PERIOD_MS);
	}
}

void app_main(void){

	xTaskCreate(&task_ds1307, "task_ds1307", 2048, NULL, 5, NULL);
}


I keep getting the following error on the begin: ds1307: i2c_master_cmd_begin: 263
This is a timeout error. I plugged in my logic analyzer and I have its output below.

I believe this is for the write();
Screen Shot 2017-05-09 at 1.06.10 PM.png
Screen Shot 2017-05-09 at 1.06.10 PM.png (12.28 KiB) Viewed 2559 times
I believe this is for the read();
Screen Shot 2017-05-09 at 1.06.23 PM.png
Screen Shot 2017-05-09 at 1.06.23 PM.png (14.66 KiB) Viewed 2559 times
Output of both.
Screen Shot 2017-05-09 at 1.06.30 PM.png
Screen Shot 2017-05-09 at 1.06.30 PM.png (35.02 KiB) Viewed 2559 times

User avatar
kolban
Posts: 1683
Joined: Mon Nov 16, 2015 4:43 pm
Location: Texas, USA

Re: DS1339 RTC

Postby kolban » Wed May 10, 2017 4:06 am

Howdy,
You didn't mention which source line in the code was throwing the exception? Do you know that information?

Another guess ... looking at the read logic ... you send a "Write" to set the address in the device and then you read 7 bytes of data. However, look closely at the last byte of data you read ... you read it and then sent an "ACK". Now compare this with the following from the data sheet:

"The register pointer automatically increments after each byte are read. The DS1307 must receive a Not Acknowledge to end a read"

See also the following reported issue:

https://github.com/espressif/esp-idf/issues/377

It may be you should NOT be reading 7 bytes with an ack ... but instead read 6 bytes with an ack followed by 1 byte with a nack.


Neil
Free book on ESP32 available here: https://leanpub.com/kolban-ESP32

embedded_systems
Posts: 10
Joined: Tue May 09, 2017 6:42 pm

Re: DS1339 RTC

Postby embedded_systems » Wed May 10, 2017 1:20 pm

Mr, Kolban. Thanks! I read that line on the data sheet as well, and I wondered if that was my problem. I also read it on the DS1307 data sheet, and that's why I didn't explore it more. I'm not sure why it works on the DS1307 without the NAck bit sent on the last read, but I have it working now on the DS1339. Below I have the modified snippet

Code: Select all

	uint8_t data[6];
	uint8_t data_end[1];
	ESP_ERROR_CHECK(i2c_master_read(cmd, data, 6, 0));
	ESP_ERROR_CHECK(i2c_master_read(cmd, data_end, 1, 1));
	
	...
	
	
	struct tm tm;
	tm.tm_sec  = bcdToInt(data[0]);
	tm.tm_min  = bcdToInt(data[1]);
	tm.tm_hour = bcdToInt(data[2]);
	tm.tm_mday = bcdToInt(data[4]);
	tm.tm_mon  = bcdToInt(data[5]) - 1; // 0-11 - Note: The month on the DS1307 is 1-12.
	tm.tm_year = bcdToInt(data_end[0]) + 100; // Years since 1900
	time_t readTime = mktime(&tm);
;

Who is online

Users browsing this forum: No registered users and 21 guests