Skip to content

Commit 43e49e5

Browse files
committed
Merge pull request #116 from triffid/feature/NXP_improved-baudrate-calculation
NXP targets: Improved baudrate calculation function
2 parents 2897644 + a249e39 commit 43e49e5

File tree

7 files changed

+287
-112
lines changed

7 files changed

+287
-112
lines changed

libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11UXX/serial_api.c

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -124,22 +124,47 @@ void serial_baud(serial_t *obj, int baudrate) {
124124
uint16_t dlv;
125125
uint8_t mv, dav;
126126
if ((PCLK % (16 * baudrate)) != 0) { // Checking for zero remainder
127-
float err_best = (float) baudrate;
128-
uint16_t dlmax = DL;
129-
for ( dlv = (dlmax/2); (dlv <= dlmax) && !hit; dlv++) {
130-
for ( mv = 1; mv <= 15; mv++) {
131-
for ( dav = 1; dav < mv; dav++) {
132-
float ratio = 1.0f + ((float) dav / (float) mv);
133-
float calcbaud = (float)PCLK / (16.0f * (float) dlv * ratio);
134-
float err = fabs(((float) baudrate - calcbaud) / (float) baudrate);
135-
if (err < err_best) {
136-
DL = dlv;
137-
DivAddVal = dav;
138-
MulVal = mv;
139-
err_best = err;
140-
if (err < 0.001f) {
141-
hit = 1;
142-
}
127+
int err_best = baudrate, b;
128+
for (mv = 1; mv < 16 && !hit; mv++)
129+
{
130+
for (dav = 0; dav < mv; dav++)
131+
{
132+
// baudrate = PCLK / (16 * dlv * (1 + (DivAdd / Mul))
133+
// solving for dlv, we get dlv = mul * PCLK / (16 * baudrate * (divadd + mul))
134+
// mul has 4 bits, PCLK has 27 so we have 1 bit headroom which can be used for rounding
135+
// for many values of mul and PCLK we have 2 or more bits of headroom which can be used to improve precision
136+
// note: X / 32 doesn't round correctly. Instead, we use ((X / 16) + 1) / 2 for correct rounding
137+
138+
if ((mv * PCLK * 2) & 0x80000000) // 1 bit headroom
139+
dlv = ((((2 * mv * PCLK) / (baudrate * (dav + mv))) / 16) + 1) / 2;
140+
else // 2 bits headroom, use more precision
141+
dlv = ((((4 * mv * PCLK) / (baudrate * (dav + mv))) / 32) + 1) / 2;
142+
143+
// datasheet says if DLL==DLM==0, then 1 is used instead since divide by zero is ungood
144+
if (dlv == 0)
145+
dlv = 1;
146+
147+
// datasheet says if dav > 0 then DL must be >= 2
148+
if ((dav > 0) && (dlv < 2))
149+
dlv = 2;
150+
151+
// integer rearrangement of the baudrate equation (with rounding)
152+
b = ((PCLK * mv / (dlv * (dav + mv) * 8)) + 1) / 2;
153+
154+
// check to see how we went
155+
b = abs(b - baudrate);
156+
if (b < err_best)
157+
{
158+
err_best = b;
159+
160+
DL = dlv;
161+
MulVal = mv;
162+
DivAddVal = dav;
163+
164+
if (b == baudrate)
165+
{
166+
hit = 1;
167+
break;
143168
}
144169
}
145170
}

libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11XX_11CXX/serial_api.c

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -121,22 +121,47 @@ void serial_baud(serial_t *obj, int baudrate) {
121121
uint16_t dlv;
122122
uint8_t mv, dav;
123123
if ((PCLK % (16 * baudrate)) != 0) { // Checking for zero remainder
124-
float err_best = (float) baudrate;
125-
uint16_t dlmax = DL;
126-
for ( dlv = (dlmax/2); (dlv <= dlmax) && !hit; dlv++) {
127-
for ( mv = 1; mv <= 15; mv++) {
128-
for ( dav = 1; dav < mv; dav++) {
129-
float ratio = 1.0f + ((float) dav / (float) mv);
130-
float calcbaud = (float)PCLK / (16.0f * (float) dlv * ratio);
131-
float err = fabs(((float) baudrate - calcbaud) / (float) baudrate);
132-
if (err < err_best) {
133-
DL = dlv;
134-
DivAddVal = dav;
135-
MulVal = mv;
136-
err_best = err;
137-
if (err < 0.001f) {
138-
hit = 1;
139-
}
124+
int err_best = baudrate, b;
125+
for (mv = 1; mv < 16 && !hit; mv++)
126+
{
127+
for (dav = 0; dav < mv; dav++)
128+
{
129+
// baudrate = PCLK / (16 * dlv * (1 + (DivAdd / Mul))
130+
// solving for dlv, we get dlv = mul * PCLK / (16 * baudrate * (divadd + mul))
131+
// mul has 4 bits, PCLK has 27 so we have 1 bit headroom which can be used for rounding
132+
// for many values of mul and PCLK we have 2 or more bits of headroom which can be used to improve precision
133+
// note: X / 32 doesn't round correctly. Instead, we use ((X / 16) + 1) / 2 for correct rounding
134+
135+
if ((mv * PCLK * 2) & 0x80000000) // 1 bit headroom
136+
dlv = ((((2 * mv * PCLK) / (baudrate * (dav + mv))) / 16) + 1) / 2;
137+
else // 2 bits headroom, use more precision
138+
dlv = ((((4 * mv * PCLK) / (baudrate * (dav + mv))) / 32) + 1) / 2;
139+
140+
// datasheet says if DLL==DLM==0, then 1 is used instead since divide by zero is ungood
141+
if (dlv == 0)
142+
dlv = 1;
143+
144+
// datasheet says if dav > 0 then DL must be >= 2
145+
if ((dav > 0) && (dlv < 2))
146+
dlv = 2;
147+
148+
// integer rearrangement of the baudrate equation (with rounding)
149+
b = ((PCLK * mv / (dlv * (dav + mv) * 8)) + 1) / 2;
150+
151+
// check to see how we went
152+
b = abs(b - baudrate);
153+
if (b < err_best)
154+
{
155+
err_best = b;
156+
157+
DL = dlv;
158+
MulVal = mv;
159+
DivAddVal = dav;
160+
161+
if (b == baudrate)
162+
{
163+
hit = 1;
164+
break;
140165
}
141166
}
142167
}

libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC13XX/serial_api.c

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -124,22 +124,47 @@ void serial_baud(serial_t *obj, int baudrate) {
124124
uint16_t dlv;
125125
uint8_t mv, dav;
126126
if ((PCLK % (16 * baudrate)) != 0) { // Checking for zero remainder
127-
float err_best = (float) baudrate;
128-
uint16_t dlmax = DL;
129-
for ( dlv = (dlmax/2); (dlv <= dlmax) && !hit; dlv++) {
130-
for ( mv = 1; mv <= 15; mv++) {
131-
for ( dav = 1; dav < mv; dav++) {
132-
float ratio = 1.0f + ((float) dav / (float) mv);
133-
float calcbaud = (float)PCLK / (16.0f * (float) dlv * ratio);
134-
float err = fabs(((float) baudrate - calcbaud) / (float) baudrate);
135-
if (err < err_best) {
136-
DL = dlv;
137-
DivAddVal = dav;
138-
MulVal = mv;
139-
err_best = err;
140-
if (err < 0.001f) {
141-
hit = 1;
142-
}
127+
int err_best = baudrate, b;
128+
for (mv = 1; mv < 16 && !hit; mv++)
129+
{
130+
for (dav = 0; dav < mv; dav++)
131+
{
132+
// baudrate = PCLK / (16 * dlv * (1 + (DivAdd / Mul))
133+
// solving for dlv, we get dlv = mul * PCLK / (16 * baudrate * (divadd + mul))
134+
// mul has 4 bits, PCLK has 27 so we have 1 bit headroom which can be used for rounding
135+
// for many values of mul and PCLK we have 2 or more bits of headroom which can be used to improve precision
136+
// note: X / 32 doesn't round correctly. Instead, we use ((X / 16) + 1) / 2 for correct rounding
137+
138+
if ((mv * PCLK * 2) & 0x80000000) // 1 bit headroom
139+
dlv = ((((2 * mv * PCLK) / (baudrate * (dav + mv))) / 16) + 1) / 2;
140+
else // 2 bits headroom, use more precision
141+
dlv = ((((4 * mv * PCLK) / (baudrate * (dav + mv))) / 32) + 1) / 2;
142+
143+
// datasheet says if DLL==DLM==0, then 1 is used instead since divide by zero is ungood
144+
if (dlv == 0)
145+
dlv = 1;
146+
147+
// datasheet says if dav > 0 then DL must be >= 2
148+
if ((dav > 0) && (dlv < 2))
149+
dlv = 2;
150+
151+
// integer rearrangement of the baudrate equation (with rounding)
152+
b = ((PCLK * mv / (dlv * (dav + mv) * 8)) + 1) / 2;
153+
154+
// check to see how we went
155+
b = abs(b - baudrate);
156+
if (b < err_best)
157+
{
158+
err_best = b;
159+
160+
DL = dlv;
161+
MulVal = mv;
162+
DivAddVal = dav;
163+
164+
if (b == baudrate)
165+
{
166+
hit = 1;
167+
break;
143168
}
144169
}
145170
}

libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/serial_api.c

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -157,22 +157,47 @@ void serial_baud(serial_t *obj, int baudrate) {
157157
uint16_t dlv;
158158
uint8_t mv, dav;
159159
if ((PCLK % (16 * baudrate)) != 0) { // Checking for zero remainder
160-
float err_best = (float) baudrate;
161-
uint16_t dlmax = DL;
162-
for ( dlv = (dlmax/2); (dlv <= dlmax) && !hit; dlv++) {
163-
for ( mv = 1; mv <= 15; mv++) {
164-
for ( dav = 1; dav < mv; dav++) {
165-
float ratio = 1.0f + ((float) dav / (float) mv);
166-
float calcbaud = (float)PCLK / (16.0f * (float) dlv * ratio);
167-
float err = fabs(((float) baudrate - calcbaud) / (float) baudrate);
168-
if (err < err_best) {
169-
DL = dlv;
170-
DivAddVal = dav;
171-
MulVal = mv;
172-
err_best = err;
173-
if (err < 0.001f) {
174-
hit = 1;
175-
}
160+
int err_best = baudrate, b;
161+
for (mv = 1; mv < 16 && !hit; mv++)
162+
{
163+
for (dav = 0; dav < mv; dav++)
164+
{
165+
// baudrate = PCLK / (16 * dlv * (1 + (DivAdd / Mul))
166+
// solving for dlv, we get dlv = mul * PCLK / (16 * baudrate * (divadd + mul))
167+
// mul has 4 bits, PCLK has 27 so we have 1 bit headroom which can be used for rounding
168+
// for many values of mul and PCLK we have 2 or more bits of headroom which can be used to improve precision
169+
// note: X / 32 doesn't round correctly. Instead, we use ((X / 16) + 1) / 2 for correct rounding
170+
171+
if ((mv * PCLK * 2) & 0x80000000) // 1 bit headroom
172+
dlv = ((((2 * mv * PCLK) / (baudrate * (dav + mv))) / 16) + 1) / 2;
173+
else // 2 bits headroom, use more precision
174+
dlv = ((((4 * mv * PCLK) / (baudrate * (dav + mv))) / 32) + 1) / 2;
175+
176+
// datasheet says if DLL==DLM==0, then 1 is used instead since divide by zero is ungood
177+
if (dlv == 0)
178+
dlv = 1;
179+
180+
// datasheet says if dav > 0 then DL must be >= 2
181+
if ((dav > 0) && (dlv < 2))
182+
dlv = 2;
183+
184+
// integer rearrangement of the baudrate equation (with rounding)
185+
b = ((PCLK * mv / (dlv * (dav + mv) * 8)) + 1) / 2;
186+
187+
// check to see how we went
188+
b = abs(b - baudrate);
189+
if (b < err_best)
190+
{
191+
err_best = b;
192+
193+
DL = dlv;
194+
MulVal = mv;
195+
DivAddVal = dav;
196+
197+
if (b == baudrate)
198+
{
199+
hit = 1;
200+
break;
176201
}
177202
}
178203
}

libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC23XX/serial_api.c

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -156,22 +156,47 @@ void serial_baud(serial_t *obj, int baudrate) {
156156
uint16_t dlv;
157157
uint8_t mv, dav;
158158
if ((PCLK % (16 * baudrate)) != 0) { // Checking for zero remainder
159-
float err_best = (float) baudrate;
160-
uint16_t dlmax = DL;
161-
for ( dlv = (dlmax/2); (dlv <= dlmax) && !hit; dlv++) {
162-
for ( mv = 1; mv <= 15; mv++) {
163-
for ( dav = 1; dav < mv; dav++) {
164-
float ratio = 1.0f + ((float) dav / (float) mv);
165-
float calcbaud = (float)PCLK / (16.0f * (float) dlv * ratio);
166-
float err = fabs(((float) baudrate - calcbaud) / (float) baudrate);
167-
if (err < err_best) {
168-
DL = dlv;
169-
DivAddVal = dav;
170-
MulVal = mv;
171-
err_best = err;
172-
if (err < 0.001f) {
173-
hit = 1;
174-
}
159+
int err_best = baudrate, b;
160+
for (mv = 1; mv < 16 && !hit; mv++)
161+
{
162+
for (dav = 0; dav < mv; dav++)
163+
{
164+
// baudrate = PCLK / (16 * dlv * (1 + (DivAdd / Mul))
165+
// solving for dlv, we get dlv = mul * PCLK / (16 * baudrate * (divadd + mul))
166+
// mul has 4 bits, PCLK has 27 so we have 1 bit headroom which can be used for rounding
167+
// for many values of mul and PCLK we have 2 or more bits of headroom which can be used to improve precision
168+
// note: X / 32 doesn't round correctly. Instead, we use ((X / 16) + 1) / 2 for correct rounding
169+
170+
if ((mv * PCLK * 2) & 0x80000000) // 1 bit headroom
171+
dlv = ((((2 * mv * PCLK) / (baudrate * (dav + mv))) / 16) + 1) / 2;
172+
else // 2 bits headroom, use more precision
173+
dlv = ((((4 * mv * PCLK) / (baudrate * (dav + mv))) / 32) + 1) / 2;
174+
175+
// datasheet says if DLL==DLM==0, then 1 is used instead since divide by zero is ungood
176+
if (dlv == 0)
177+
dlv = 1;
178+
179+
// datasheet says if dav > 0 then DL must be >= 2
180+
if ((dav > 0) && (dlv < 2))
181+
dlv = 2;
182+
183+
// integer rearrangement of the baudrate equation (with rounding)
184+
b = ((PCLK * mv / (dlv * (dav + mv) * 8)) + 1) / 2;
185+
186+
// check to see how we went
187+
b = abs(b - baudrate);
188+
if (b < err_best)
189+
{
190+
err_best = b;
191+
192+
DL = dlv;
193+
MulVal = mv;
194+
DivAddVal = dav;
195+
196+
if (b == baudrate)
197+
{
198+
hit = 1;
199+
break;
175200
}
176201
}
177202
}

libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC408X/serial_api.c

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -147,22 +147,47 @@ void serial_baud(serial_t *obj, int baudrate) {
147147
uint16_t dlv;
148148
uint8_t mv, dav;
149149
if ((PCLK % (16 * baudrate)) != 0) { // Checking for zero remainder
150-
float err_best = (float) baudrate;
151-
uint16_t dlmax = DL;
152-
for ( dlv = (dlmax/2); (dlv <= dlmax) && !hit; dlv++) {
153-
for ( mv = 1; mv <= 15; mv++) {
154-
for ( dav = 1; dav < mv; dav++) {
155-
float ratio = 1.0f + ((float) dav / (float) mv);
156-
float calcbaud = (float)PCLK / (16.0f * (float) dlv * ratio);
157-
float err = fabs(((float) baudrate - calcbaud) / (float) baudrate);
158-
if (err < err_best) {
159-
DL = dlv;
160-
DivAddVal = dav;
161-
MulVal = mv;
162-
err_best = err;
163-
if (err < 0.001f) {
164-
hit = 1;
165-
}
150+
int err_best = baudrate, b;
151+
for (mv = 1; mv < 16 && !hit; mv++)
152+
{
153+
for (dav = 0; dav < mv; dav++)
154+
{
155+
// baudrate = PCLK / (16 * dlv * (1 + (DivAdd / Mul))
156+
// solving for dlv, we get dlv = mul * PCLK / (16 * baudrate * (divadd + mul))
157+
// mul has 4 bits, PCLK has 27 so we have 1 bit headroom which can be used for rounding
158+
// for many values of mul and PCLK we have 2 or more bits of headroom which can be used to improve precision
159+
// note: X / 32 doesn't round correctly. Instead, we use ((X / 16) + 1) / 2 for correct rounding
160+
161+
if ((mv * PCLK * 2) & 0x80000000) // 1 bit headroom
162+
dlv = ((((2 * mv * PCLK) / (baudrate * (dav + mv))) / 16) + 1) / 2;
163+
else // 2 bits headroom, use more precision
164+
dlv = ((((4 * mv * PCLK) / (baudrate * (dav + mv))) / 32) + 1) / 2;
165+
166+
// datasheet says if DLL==DLM==0, then 1 is used instead since divide by zero is ungood
167+
if (dlv == 0)
168+
dlv = 1;
169+
170+
// datasheet says if dav > 0 then DL must be >= 2
171+
if ((dav > 0) && (dlv < 2))
172+
dlv = 2;
173+
174+
// integer rearrangement of the baudrate equation (with rounding)
175+
b = ((PCLK * mv / (dlv * (dav + mv) * 8)) + 1) / 2;
176+
177+
// check to see how we went
178+
b = abs(b - baudrate);
179+
if (b < err_best)
180+
{
181+
err_best = b;
182+
183+
DL = dlv;
184+
MulVal = mv;
185+
DivAddVal = dav;
186+
187+
if (b == baudrate)
188+
{
189+
hit = 1;
190+
break;
166191
}
167192
}
168193
}

0 commit comments

Comments
 (0)