Wednesday, 25 March 2015

pcb design - Defining a circular cutout in a pad in Altium


I'm creating the footprint for a Wurth inductor, 744043100. The recommended land pattern is below.



744043100 recommended land pattern


They use a radius 1.8 mm circle in the middle of the component to define a void in the pad. I'm trying to create the same shape in Altium, but am running into some trouble with it. In the screenshot below, I've tried two methods.


Altium footprint implementation.


Pad 2 uses a region with six vertices and an arc to define the curved region, which works but seems prone to some round-off errors. It's not a big deal, but I can measure my radius to be ~1.76 mm at y = 0 mm. It also requires some math to find the vertices and arc angle, and no one likes that.


Pad 1 shows what I'd like to be able to do. My preference here would be to define a rectangular fill, define a circle of radius 1.8 mm, and use the circle as a cutout to modify the fill. Is it possible to do this from within the PCB library editor? Is there another way to define this shape that I've missed?


I'm using Altium 18.1.7.



Answer



I would do this by defining the outline and then creating a solid region from the outline. Eg. Snap grid set to 0.025mm. Set at 0,0 for center so that the center arc can be used to snap to the ends of the lines (do them first). Takes just a few seconds to draw this.


enter image description here


Then Tools->Convert->Create Region from Selected Primitives



enter image description here


And then add a pad to the region etc.


AC constant-current source design


I want to provide a fairly constant current (say 10mA RMS, peak 20mA, of 60Hz AC, using a 120V supply) to a load of highly variable resistance. It doesn't have to be super-clean or precise, but should be able to adjust within a few cycles and never stray more than 100% from set current level.


The contemplated load is an electrolytic chemical reactor. It'll be a lot easier to tell once I can feed some current through actual reagents, but best guess right now is that resistance can vary from single-digit to thousands of ohms depending on all sorts of things (temperature, reagent phase, etc.). So I'll want to pick a current and be able to hold that relatively constant as all the other internal and external parameters vary.


What components or circuits can accomplish this?




Answer



The simplest way to build an active AC constant-current source takes only 4 parts:



  • A suitably rated bridge rectifier (600PIV, 1A works)

  • A suitable resistor (you'll have to try several values)

  • A HV depletion MOSFET such as the IXTH20N50D

  • And a bit of heatsinking -- the FET dissipates a fair bit of power


Theory of operation: This is your standard JFET constant current source, just bigger thanks to the power depletion MOSFET. AC operation is provided by connecting it to the DC terminals of a bridge rectifier. (RL is a sample load -- whatever load you wish just connects in series, the circuit is insensitive to load position and polarity.)


schematic



simulate this circuit – Schematic created using CircuitLab


Tuesday, 24 March 2015

led - Not understanding Forward Voltage and Voltage Drop


I have a simple circuit:


+12V -- R1 -- LED1 -- LED2 -- LED3 -- ground


Falstad simulation link



If the Forward Voltage of an LED is 3V, and the Forward Current is 20mA, I can (I believe) calculate the required resistance of the resistor as (12V - (3 * 3V)) / 0.02A = 150Ω.


From what I understand, that should give me a Voltage Drop of 3V over the resistor and each LED respectively, and a current of 20mA through the circuit - perfect.


In the simulation of this circuit, I get a Voltage Drop of 4.01V, 2.66V, 2.66V, 2.66V respectively, and a current of 26.74mA through the circuit, which is too high for the LEDs.


This makes me think that I don't understand the relationship between Forward Voltage and Voltage Drop, and therefore, how am I supposed to calculate a correct resistor value that won't burn out the LEDs?


Apologies if this is asked a lot or is really simple, but I've been searching for ages and haven't come up with anything.



Answer



For your simulation, you specify the led's forward voltage as "3V at 1A". This means the forward voltage of the leds at about 20mA will be much lower.


Everything is right there, you just need to read the leds datasheet to find the forward voltage at arount 20mA.


active filter - Finding the cut-off frequency


Find the cut-off frequency of this filter:


schematic



My attempt:


$$\text{H}\space_{\left(\omega\right)}=\frac{\text{R}_1+j\omega\text{L}}{\text{R}_1+\text{R}_2+j\omega\text{L}}=\frac{\text{R}_1+j\omega\text{L}}{\text{R}_1+\text{R}_2+j\omega\text{L}}\cdot\frac{\text{R}_1+\text{R}_2-j\omega\text{L}}{\text{R}_1+\text{R}_2-j\omega\text{L}}=$$ $$\frac{\text{R}_1^2+\text{R}_1\text{R}_2+\left(\omega\text{L}\right)^2+j\omega\text{L}\text{R}_2}{\left(\text{R}_1+\text{R}_2\right)^2+\left(\omega\text{L}\right)^2}$$


So when you're looking for the cut-off frequency you can say:


$$\Re\left(\text{H}\space_{\left(\omega\right)}\right)=\Im\left(\text{H}\space_{\left(\omega\right)}\right)$$


So we get:


$$\text{R}_1^2+\text{R}_1\text{R}_2+\left(\omega\text{L}\right)^2=\omega\text{L}\text{R}_2\Longleftrightarrow$$ $$\left(\omega\text{L}\right)^2-\omega\text{L}\text{R}_2+\text{R}_1^2+\text{R}_1\text{R}_2=0\Longleftrightarrow$$ $$\omega^2\text{L}^2-\omega\text{L}\text{R}_2+\text{R}_1^2+\text{R}_1\text{R}_2=0\Longleftrightarrow$$ $$\omega=\frac{\text{L}\text{R}_2\pm\sqrt{\left(-\text{L}\text{R}_2\right)^2-4\cdot \text{L}^2\cdot \left(\text{R}_1^2+\text{R}_1\text{R}_2\right)}}{2\cdot \text{L}^2}\Longleftrightarrow$$ $$\omega=\frac{\text{L}\text{R}_2\pm\sqrt{\left(\text{L}\text{R}_2\right)^2-4\cdot \text{L}^2\cdot \left(\text{R}_1^2+\text{R}_1\text{R}_2\right)}}{2\cdot \text{L}^2}$$


Am I doing something wrong?




voltage - Why is mains power sometimes 110V and other times 120V?


(The same question can apply to locations with 220/240V mains, if I am not mistaken.)


Frequently I see mixed ratings indicating that something is suitable for 110, 115, 118 or 120V (in the US). I've always referred to mains power as 120V but with the understanding that it varies because of:



  • Different means of generation (number of phases, etc.)

  • Line losses and imperfect conditions


When designing something, should one always test using the lowest expected voltage (110)? What reasons are there for the differences in mains voltage?



Answer



In the US, the electric utilities are supposed to deliver power to residential customers at anywhere between 110 and 125 VAC RMS. The value 117 (or 117.5 or 118) is often seen on products, because that is the middle of the specified range.



If you're developing a product for general sale, it would be prudent to add a testing margin that's at least 5% or even 10% beyond the nominal range — perhaps 100 to 140 VAC RMS.


pcb design - Seperate Signal Planes in Eagle



I am trying to make separate signal planes in eagle using the polygon tool. The problem is that when I draw the first polygon, regardless of whether I draw it small or large once I name it to GND and hit the "Ratsnest" tool, it will just occupy the whole space of the PCB leaving no space for other planes. How can I fix that?


Also I need one of the planes to be exposed copper, by drawing a polygon on either the bstop or tstop layers, I am getting what I need. The problem is that I don't know how to connect it to another part (say a transistor)?



Answer



Give each one a seperate rank (found in the properties dialogue). The lower the number the higher the priority. So a polygon of rank 1 will be drawn first, then ones with a rank of 2 will be drawn next (being cut away by the higher priority polygon outlines).


This will allow you to have polygons inside polygons.




The second part of your question, if you name the polygon with the same name as the net you want it to connect to, then you can just route a trace staring from anywhere within the polygon and Eagle will know they are meant to be connected.


Monday, 23 March 2015

microcontroller - Serial Output returns wrong ASCII


I am using a FTDI cable and connected it with my mac. I can connect successfully with my serial terminal on my mac via the cable and can input text on my keyboard to be transmitted to the AVR. When the program starts I expect a "Hello World" message to appear on my serial terminal. But instead I receive this output on the screen:


enter image description here The terminal settings are enter image description here



enter image description here enter image description here


enter image description here


The code is this:


// ------- Preamble -------- //
#include
#include
#include "pinDefines.h"
#include "USART.h"

int main(void) {

char serialCharacter;

// -------- Inits --------- //
LED_DDR = 0xff; /* set up LEDs for output */
initUSART();
printString("Hello World!\r\n"); /* to test */

// ------ Event loop ------ //
while (1) {


serialCharacter = receiveByte();
transmitByte(serialCharacter);
LED_PORT = serialCharacter;
/* display ascii/numeric value of character */

} /* End event loop */
return 0;
}

The USART.c file contains:



#include 
#include "USART.h"
#include
#define BAUD 9600

void initUSART(void) { /* requires BAUD */
UBRR0H = UBRRH_VALUE; /* defined in setbaud.h */
UBRR0L = UBRRL_VALUE;
#if USE_2X
UCSR0A |= (1 << U2X0);

#else
UCSR0A &= ~(1 << U2X0);
#endif
/* Enable USART transmitter/receiver */
UCSR0B = (1 << TXEN0) | (1 << RXEN0);
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); /* 8 data bits, 1 stop bit */
}

void transmitByte(uint8_t data) {
/* Wait for empty transmit buffer */

loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = data; /* send data */
}

uint8_t receiveByte(void) {
loop_until_bit_is_set(UCSR0A, RXC0); /* Wait for incoming data */
return UDR0; /* return register value */
}

/* Here are a bunch of useful printing commands */


void printString(const char myString[]) {
uint8_t i = 0;
while (myString[i]) {
transmitByte(myString[i]);
i++;
}
}

void readString(char myString[], uint8_t maxLength) {

char response;
uint8_t i;
i = 0;
while (i < (maxLength - 1)) { /* prevent over-runs */
response = receiveByte();
transmitByte(response); /* echo */
if (response == '\r') { /* enter marks the end */
break;
}
else {

myString[i] = response; /* add in a letter */
i++;
}
}
myString[i] = 0; /* terminal NULL character */
}

void printByte(uint8_t byte) {
/* Converts a byte to a string of decimal text, sends it */
transmitByte('0' + (byte / 100)); /* Hundreds */

transmitByte('0' + ((byte / 10) % 10)); /* Tens */
transmitByte('0' + (byte % 10)); /* Ones */
}

void printWord(uint16_t word) {
transmitByte('0' + (word / 10000)); /* Ten-thousands */
transmitByte('0' + ((word / 1000) % 10)); /* Thousands */
transmitByte('0' + ((word / 100) % 10)); /* Hundreds */
transmitByte('0' + ((word / 10) % 10)); /* Tens */
transmitByte('0' + (word % 10)); /* Ones */

}

void printBinaryByte(uint8_t byte) {
/* Prints out a byte as a series of 1's and 0's */
uint8_t bit;
for (bit = 7; bit < 255; bit--) {
if (bit_is_set(byte, bit))
transmitByte('1');
else
transmitByte('0');

}
}

char nibbleToHexCharacter(uint8_t nibble) {
/* Converts 4 bits into hexadecimal */
if (nibble < 10) {
return ('0' + nibble);
}
else {
return ('A' + nibble - 10);

}
}

void printHexByte(uint8_t byte) {
/* Prints a byte as its hexadecimal equivalent */
uint8_t nibble;
nibble = (byte & 0b11110000) >> 4;
transmitByte(nibbleToHexCharacter(nibble));
nibble = byte & 0b00001111;
transmitByte(nibbleToHexCharacter(nibble));

}

uint8_t getNumber(void) {
// Gets a numerical 0-255 from the serial port.
// Converts from string to number.
char hundreds = '0';
char tens = '0';
char ones = '0';
char thisChar = '0';
do { /* shift over */

hundreds = tens;
tens = ones;
ones = thisChar;
thisChar = receiveByte(); /* get a new character */
transmitByte(thisChar); /* echo */
} while (thisChar != '\r'); /* until type return */
return (100 * (hundreds - '0') + 10 * (tens - '0') + ones - '0');
}

Answer



I ran into this same problem, and the answer provided by @bence_kaulics is what got me through it, with one additional point:



I am in the same situation as @secs360:



  1. atmega328p

  2. working through chapter Chapter 5 (USART) in the book Make AVR Programming (the source of the code sample provided by @secs360)

  3. I can program my chip (blink tests work), but the serial feedback loop responds with incorrect characters. Various combinations of BAUD settings in the code, or in the serial terminal, fail to resolve the issue.


Steps to fix:


First, confirm I have set the clock correctly:



Fuses OK (E:FF, H:D9, L:62)




Checking these against a fuse calculator, I see they are the default values: the MCU is set to use the internal RC oscillator at 1 MHz.


This means I should set the CPU speed (in the makefile for the chapter exercises in this case):


F_CPU = 1000000UL

I can also set the BAUD value in the same location. 9600 should work:


BAUD  = 9600UL

So far so good. However, the book uses a different formula for calculating the UBRRn register values. @bence_kaulics provides the formula, from the datasheet.


(Perhaps the difference is due to the book being written for atmega168 chips? I don't know. But whatever the source, we need to use the correct value here.)



There is one more piece of information! If we want to use 9600 BAUD, we will have an error of -7% with standard transmission speed, according to the datasheet. If we double the transmission speed, our error drops to 0.2%. To do this, we don't use the formula provided by @bence_kaulics, but instead use ((F_CPU)/(BAUD*8UL)-1), and set the U2X0 bit.


I did that by modifying the initUSART function in the USART.c file:


void initUSART(void) {                                /* requires BAUD */
#define BAUDRATE ((F_CPU)/(BAUD*8UL)-1) // set baud rate value for UBRR
UBRR0H = (BAUDRATE>>8); // shift the register right by 8 bits to get the upper 8 bits
UBRR0L = BAUDRATE; // set baud rate

UCSR0A |= (1 << U2X0); // double transmission speed

/* Enable USART transmitter/receiver */

UCSR0B = (1 << TXEN0) | (1 << RXEN0);
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); /* 8 data bits, 1 stop bit */
}

The original version from the book uses logic in the setbaud.h file to determine whether or not to double the transmission speed. I don't understand all of it, and so I'm not sure if the problem is the formula used for the BAUDRATE, or USE_2X, or both. Whatever it is, the code above has finally got my atmega328p speaking properly over the serial interface.


arduino - Can I use TI&#39;s cc2541 BLE as micro controller to perform operations/ processing instead of ATmega328P AU to save cost?

I am using arduino pro mini (which contains Atmega328p AU ) along with cc2541(HM-10) to process and transfer data over BLE to smartphone. I...