Change in osmo-ccid-firmware[master]: add function to set baudrate

Kévin Redon gerrit-no-reply at lists.osmocom.org
Thu May 2 13:56:21 UTC 2019


Kévin Redon has uploaded this change for review. ( https://gerrit.osmocom.org/13845


Change subject: add function to set baudrate
......................................................................

add function to set baudrate

it will set the GCLK as SERCOM core clock with the lowest baud
rate error and set the closest baud rate in the SERCOM peripheral.

Change-Id: I01db273f4c8170a4942049653c575010b93296ce
---
M sysmoOCTSIM/main.c
1 file changed, 78 insertions(+), 1 deletion(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-ccid-firmware refs/changes/45/13845/1

diff --git a/sysmoOCTSIM/main.c b/sysmoOCTSIM/main.c
index 47d1cd1..70099e1 100644
--- a/sysmoOCTSIM/main.c
+++ b/sysmoOCTSIM/main.c
@@ -18,12 +18,14 @@
 
 #include <stdlib.h>
 #include <stdio.h>
+#include <math.h>
 #include <parts.h>
 #include <hal_cache.h>
 #include <hri_port_e54.h>
 
 #include "atmel_start.h"
 #include "atmel_start_pins.h"
+#include "config/hpl_gclk_config.h"
 
 #include "i2c_bitbang.h"
 #include "octsim_i2c.h"
@@ -39,6 +41,21 @@
 {
 }
 
+/** possible clock sources for the SERCOM peripheral
+ *  warning: the definition must match the GCLK configuration
+ */
+static const uint8_t sercom_glck_sources[] = {GCLK_PCHCTRL_GEN_GCLK2_Val, GCLK_PCHCTRL_GEN_GCLK4_Val, GCLK_PCHCTRL_GEN_GCLK6_Val};
+
+/** possible clock frequencies in MHz for the SERCOM peripheral
+ *  warning: the definition must match the GCLK configuration
+ */
+static const double sercom_glck_freqs[] = {100E6 / CONF_GCLK_GEN_2_DIV, 100E6 / CONF_GCLK_GEN_4_DIV, 120E6 / CONF_GCLK_GEN_6_DIV};
+
+/** the GCLK ID for the SERCOM SIM peripherals
+ *  @note: used as index for PCHCTRL
+ */
+static const uint8_t SIM_peripheral_GCLK_ID[] = {SERCOM0_GCLK_ID_CORE, SERCOM1_GCLK_ID_CORE, SERCOM2_GCLK_ID_CORE, SERCOM3_GCLK_ID_CORE, SERCOM4_GCLK_ID_CORE, SERCOM5_GCLK_ID_CORE, SERCOM6_GCLK_ID_CORE, SERCOM7_GCLK_ID_CORE};
+
 static void board_init()
 {
 	int i;
@@ -81,6 +98,66 @@
 	return slotnr;
 }
 
+/** change baud rate of card slot
+ *  @param[in] slotnr slot number for which the baud rate should be set
+ *  @param[in] baudrate baud rate in bps to set
+ *  @return if the baud rate has been set, else a parameter is out of range
+ */
+static bool slot_set_baudrate(uint8_t slotnr, uint32_t baudrate)
+{
+	ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
+
+	// calculate the error corresponding to the clock sources
+	uint16_t bauds[ARRAY_SIZE(sercom_glck_freqs)];
+	double errors[ARRAY_SIZE(sercom_glck_freqs)];
+	for (uint8_t i = 0; i < ARRAY_SIZE(sercom_glck_freqs); i++) {
+		double freq = sercom_glck_freqs[i]; // remember possible SERCOM frequency
+		uint32_t min = freq / (2 * (255 + 1)); // calculate the minimum baud rate for this frequency
+		uint32_t max = freq / (2 * (0 + 1)); // calculate the maximum baud rate for this frequency
+		if (baudrate < min || baudrate > max) { // baud rate it out of supported range
+			errors[i] = NAN;
+		} else {
+			uint16_t baud = round(freq / (2 * baudrate) - 1);
+			bauds[i] = baud;
+			double actual = freq / (2 * (baud + 1));
+			errors[i] = fabs(1.0 - (actual / baudrate));
+		}
+	}
+
+	// find the smallest error
+	uint8_t best = ARRAY_SIZE(sercom_glck_freqs);
+	for (uint8_t i = 0; i < ARRAY_SIZE(sercom_glck_freqs); i++) {
+		if (isnan(errors[i])) {
+			continue;
+		}
+		if (best >= ARRAY_SIZE(sercom_glck_freqs)) {
+			best = i;
+		} else if (errors[i] < errors[best]) {
+			best = i;
+		}
+	}
+	if (best >= ARRAY_SIZE(sercom_glck_freqs)) { // found no clock supporting this baud rate
+		return false;
+	}
+
+	// set clock and baud rate
+	struct usart_async_descriptor* slot = SIM_peripheral_descriptors[slotnr]; // get slot
+	if (NULL == slot) {
+		return false;
+	}
+	printf("(%u) switching SERCOM clock to GCLK%u (freq = %lu kHz) and baud rate to %lu bps (baud = %u)\r\n", slotnr, (best + 1) * 2, (uint32_t)(round(sercom_glck_freqs[best] / 1000)), baudrate, bauds[best]);
+	while (!usart_async_is_tx_empty(slot)); // wait for transmission to complete (WARNING no timeout)
+	usart_async_disable(slot); // disable SERCOM peripheral
+	hri_gclk_clear_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], (1 << GCLK_PCHCTRL_CHEN_Pos)); // disable clock for this peripheral
+	while (hri_gclk_get_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], (1 << GCLK_PCHCTRL_CHEN_Pos))); // wait until clock is really disabled
+	// it does not seem we need to completely disable the peripheral using hri_mclk_clear_APBDMASK_SERCOMn_bit
+	hri_gclk_write_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], sercom_glck_sources[best] | (1 << GCLK_PCHCTRL_CHEN_Pos)); // set peripheral core clock and re-enable it
+	usart_async_set_baud_rate(slot, bauds[best]); // set the new baud rate
+	usart_async_enable(slot); // re-enable SERCOM peripheral
+
+	return true;
+}
+
 DEFUN(sim_status, cmd_sim_status, "sim-status", "Get state of specified NCN8025")
 {
 	struct ncn8025_settings settings;
@@ -245,7 +322,7 @@
 	// TODO wait some time for card to be completely deactivated
 	usart_async_flush_rx_buffer(SIM_peripheral_descriptors[slotnr]); // flush RX buffer to start from scratch
 
-	//usart_async_set_baud_rate(SIM_peripheral_descriptors[slotnr], 2500000 / (372 / 1)); // set USART baud rate to match the interface (f = 2.5 MHz) and card default settings (Fd = 372, Dd = 1)
+	slot_set_baudrate(slotnr, 2500000 / (372 / 1)); // set USART baud rate to match the interface (f = 2.5 MHz) and card default settings (Fd = 372, Dd = 1)
 	// set clock to lowest frequency (20 MHz / 8 = 2.5 MHz)
 	// note: according to ISO/IEC 7816-3:2006 section 5.2.3 the minimum value is 1 MHz, and maximum is 5 MHz during activation
 	settings.clkdiv = SIM_CLKDIV_8;

-- 
To view, visit https://gerrit.osmocom.org/13845
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-ccid-firmware
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I01db273f4c8170a4942049653c575010b93296ce
Gerrit-Change-Number: 13845
Gerrit-PatchSet: 1
Gerrit-Owner: Kévin Redon <kredon at sysmocom.de>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20190502/7e1025e9/attachment.html>


More information about the gerrit-log mailing list