<p>Harald Welte <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/13845">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  Harald Welte: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">add function to set baudrate<br><br>it will set the GCLK as SERCOM core clock with the lowest baud<br>rate error and set the closest baud rate in the SERCOM peripheral.<br><br>Change-Id: I01db273f4c8170a4942049653c575010b93296ce<br>---<br>M sysmoOCTSIM/main.c<br>1 file changed, 78 insertions(+), 1 deletion(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/sysmoOCTSIM/main.c b/sysmoOCTSIM/main.c</span><br><span>index 47d1cd1..70099e1 100644</span><br><span>--- a/sysmoOCTSIM/main.c</span><br><span>+++ b/sysmoOCTSIM/main.c</span><br><span>@@ -18,12 +18,14 @@</span><br><span> </span><br><span> #include <stdlib.h></span><br><span> #include <stdio.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <math.h></span><br><span> #include <parts.h></span><br><span> #include <hal_cache.h></span><br><span> #include <hri_port_e54.h></span><br><span> </span><br><span> #include "atmel_start.h"</span><br><span> #include "atmel_start_pins.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "config/hpl_gclk_config.h"</span><br><span> </span><br><span> #include "i2c_bitbang.h"</span><br><span> #include "octsim_i2c.h"</span><br><span>@@ -39,6 +41,21 @@</span><br><span> {</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/** possible clock sources for the SERCOM peripheral</span><br><span style="color: hsl(120, 100%, 40%);">+ *  warning: the definition must match the GCLK configuration</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static const uint8_t sercom_glck_sources[] = {GCLK_PCHCTRL_GEN_GCLK2_Val, GCLK_PCHCTRL_GEN_GCLK4_Val, GCLK_PCHCTRL_GEN_GCLK6_Val};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/** possible clock frequencies in MHz for the SERCOM peripheral</span><br><span style="color: hsl(120, 100%, 40%);">+ *  warning: the definition must match the GCLK configuration</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static const double sercom_glck_freqs[] = {100E6 / CONF_GCLK_GEN_2_DIV, 100E6 / CONF_GCLK_GEN_4_DIV, 120E6 / CONF_GCLK_GEN_6_DIV};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/** the GCLK ID for the SERCOM SIM peripherals</span><br><span style="color: hsl(120, 100%, 40%);">+ *  @note: used as index for PCHCTRL</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+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};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static void board_init()</span><br><span> {</span><br><span>    int i;</span><br><span>@@ -81,6 +98,66 @@</span><br><span>  return slotnr;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/** change baud rate of card slot</span><br><span style="color: hsl(120, 100%, 40%);">+ *  @param[in] slotnr slot number for which the baud rate should be set</span><br><span style="color: hsl(120, 100%, 40%);">+ *  @param[in] baudrate baud rate in bps to set</span><br><span style="color: hsl(120, 100%, 40%);">+ *  @return if the baud rate has been set, else a parameter is out of range</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static bool slot_set_baudrate(uint8_t slotnr, uint32_t baudrate)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ // calculate the error corresponding to the clock sources</span><br><span style="color: hsl(120, 100%, 40%);">+     uint16_t bauds[ARRAY_SIZE(sercom_glck_freqs)];</span><br><span style="color: hsl(120, 100%, 40%);">+        double errors[ARRAY_SIZE(sercom_glck_freqs)];</span><br><span style="color: hsl(120, 100%, 40%);">+ for (uint8_t i = 0; i < ARRAY_SIZE(sercom_glck_freqs); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              double freq = sercom_glck_freqs[i]; // remember possible SERCOM frequency</span><br><span style="color: hsl(120, 100%, 40%);">+             uint32_t min = freq / (2 * (255 + 1)); // calculate the minimum baud rate for this frequency</span><br><span style="color: hsl(120, 100%, 40%);">+          uint32_t max = freq / (2 * (0 + 1)); // calculate the maximum baud rate for this frequency</span><br><span style="color: hsl(120, 100%, 40%);">+            if (baudrate < min || baudrate > max) { // baud rate it out of supported range</span><br><span style="color: hsl(120, 100%, 40%);">+                  errors[i] = NAN;</span><br><span style="color: hsl(120, 100%, 40%);">+              } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      uint16_t baud = round(freq / (2 * baudrate) - 1);</span><br><span style="color: hsl(120, 100%, 40%);">+                     bauds[i] = baud;</span><br><span style="color: hsl(120, 100%, 40%);">+                      double actual = freq / (2 * (baud + 1));</span><br><span style="color: hsl(120, 100%, 40%);">+                      errors[i] = fabs(1.0 - (actual / baudrate));</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   // find the smallest error</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t best = ARRAY_SIZE(sercom_glck_freqs);</span><br><span style="color: hsl(120, 100%, 40%);">+ for (uint8_t i = 0; i < ARRAY_SIZE(sercom_glck_freqs); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (isnan(errors[i])) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (best >= ARRAY_SIZE(sercom_glck_freqs)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       best = i;</span><br><span style="color: hsl(120, 100%, 40%);">+             } else if (errors[i] < errors[best]) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     best = i;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (best >= ARRAY_SIZE(sercom_glck_freqs)) { // found no clock supporting this baud rate</span><br><span style="color: hsl(120, 100%, 40%);">+           return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   // set clock and baud rate</span><br><span style="color: hsl(120, 100%, 40%);">+    struct usart_async_descriptor* slot = SIM_peripheral_descriptors[slotnr]; // get slot</span><br><span style="color: hsl(120, 100%, 40%);">+ if (NULL == slot) {</span><br><span style="color: hsl(120, 100%, 40%);">+           return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     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]);</span><br><span style="color: hsl(120, 100%, 40%);">+        while (!usart_async_is_tx_empty(slot)); // wait for transmission to complete (WARNING no timeout)</span><br><span style="color: hsl(120, 100%, 40%);">+     usart_async_disable(slot); // disable SERCOM peripheral</span><br><span style="color: hsl(120, 100%, 40%);">+       hri_gclk_clear_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], (1 << GCLK_PCHCTRL_CHEN_Pos)); // disable clock for this peripheral</span><br><span style="color: hsl(120, 100%, 40%);">+    while (hri_gclk_get_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], (1 << GCLK_PCHCTRL_CHEN_Pos))); // wait until clock is really disabled</span><br><span style="color: hsl(120, 100%, 40%);">+    // it does not seem we need to completely disable the peripheral using hri_mclk_clear_APBDMASK_SERCOMn_bit</span><br><span style="color: hsl(120, 100%, 40%);">+    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</span><br><span style="color: hsl(120, 100%, 40%);">+       usart_async_set_baud_rate(slot, bauds[best]); // set the new baud rate</span><br><span style="color: hsl(120, 100%, 40%);">+        usart_async_enable(slot); // re-enable SERCOM peripheral</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> DEFUN(sim_status, cmd_sim_status, "sim-status", "Get state of specified NCN8025")</span><br><span> {</span><br><span>      struct ncn8025_settings settings;</span><br><span>@@ -245,7 +322,7 @@</span><br><span>      // TODO wait some time for card to be completely deactivated</span><br><span>         usart_async_flush_rx_buffer(SIM_peripheral_descriptors[slotnr]); // flush RX buffer to start from scratch</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   //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)</span><br><span style="color: hsl(120, 100%, 40%);">+        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)</span><br><span>     // set clock to lowest frequency (20 MHz / 8 = 2.5 MHz)</span><br><span>      // 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</span><br><span>   settings.clkdiv = SIM_CLKDIV_8;</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/13845">change 13845</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/13845"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-ccid-firmware </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I01db273f4c8170a4942049653c575010b93296ce </div>
<div style="display:none"> Gerrit-Change-Number: 13845 </div>
<div style="display:none"> Gerrit-PatchSet: 3 </div>
<div style="display:none"> Gerrit-Owner: Kévin Redon <kredon@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Harald Welte <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder (1000002) </div>