FN-M16P MP3 player (Part 2)

Part 1, 2

As seen in the previous post, the MCU (e.g. arduino) and the module are talking each other through a serial communication (UART) at a quite modest rate of 9600 baud. Data is exchanged as packets of 10 bytes according to the following structure:

Byte#	Function		Value	Comments
0	Start Byte		0x7E	constant
1	Version Info		0xFF	my module returns 8, any input value will work
2	Number of bytes		0x06	constant
3	Command 		0xXX	See datasheet
4	Command feedback	0xXX	0x00 or 0x01
5	Parameter		0xXX	parameter MSB, see datasheet
6	Parameter		0xXX	parameter LSB, see datasheet
7	Checksum		0xXX	checksum MSB
8	Checksum		0xXX	checksum LSB
9	End command		0xEF	constant

The checksum is computed over the 6 bits proceeding it. Computing the checksum is fairly easy: sum the 6 bytes and negate them. Then map the Most Significant and the Least Significant Bytes (MSB & LSB).

16 bits can be used for the parameter settings. Various cases happen:

  • Some commands do not require a parameter, then enter any byte value
  • Some commands require an 8 bit parameter, then enter this parameter as the LSB and enter any value for the LSB
  • Some commands require two 8 bit parameters, then enter each parameter as the LSB and the LSB
  • Some commands require a 16 bits parameter, then map the MSB ((value >> 8) & OxFF) and LSB (value & OxFF) from the parameter and enter then as the parameter MSB and LSB
  • One command requires a 4 bits parameter and a 12 bits parameter, then apply a 4 bits shift to the first parameter and map them to the MSB, the 4 next bits are shifted from the second parameter and the remaining bits are mapped to the LSB.

The command feedback is optional and may be necessary in harsh environments. However, the risk is low that the UART will fail to exchange data at 9600 bauds so that I did not implement this option in my code. Surprisingly, the checksum is not mandatory and the checksum bytes might be omitted, leading to 8 bytes long frames. However, I maintained this minimal integrity protection level in the data  communication.

Next is a link to a spreadsheet that I used in my early testing which you may find helpful for debugging. >Link<

While most commands do not echo data from the device, some do. This is the case for the commands echoing the current sound level, the number of tracks on device, etc. Data is transmitted back once the full incoming frame is read and decoded by the device (half duplex transmission). Errors are reported as command 0x40.

The library that I built uses general purpose functions that relate to the “sound tracks reader” mode and to the “sound tracks manager” mode. In its early version, it contains a light management of errors.

Next is a copy of the command launcher function

/*
Execute command using its parameters
The returned value is passed by reference and the function returns error codes (DFP_ERR_NONE=0=no error)
*/
uint8_t PlainDFP::execCmd(uint8_t CMD, uint8_t paramMSB, uint8_t paramLSB, uint16_t *retValue) 
{
	uint8_t error = DFP_ERR_NONE;
	uint8_t vBuffer[10];
	/* Build the command line */
	vBuffer[0] = 0x7E; 					/* Start byte (constant) */
	vBuffer[1] = 0xFF; 					/* Version byte: any value */
	vBuffer[2] = 0x06; 					/* Data length (checksum not included) always 6 */
	vBuffer[3] = CMD;  					/* Actual command */
	vBuffer[4] = 0x00; 					/* Feedback request: 0=no, 1=yes */
	vBuffer[5] = paramMSB; 				/* Parameter MSB */
	vBuffer[6] = paramLSB; 				/* Parameter LSB */
	vBuffer[7] = 0xFF; 					/* Check sum MSB */
	vBuffer[8] = 0xFF; 					/* Check sum LSB */
	vBuffer[9] = 0xEF; 					/* End byte (constant) */
	/* Compute and record checksum */
	int16_t checksum = checkSum(vBuffer);
	vBuffer[7] = ((checksum >> 8) & 0xFF); 		/* Check sum MSB */
	vBuffer[8] = (checksum & 0xFF); 			/* Check sum LSB */
	/* Send the command line to the module */
	for (uint8_t i = 0; i < 10; i++)
	{
		_serial->write(vBuffer[i]);
	}
	/* If the command is supposed to echo a feed back */
	if (CMD > 0x20)
	{
		delay(100);
		if (_serial->available() >= 10) 
		{
			/* Record answer in buffer */
			for (uint8_t i = 0; i < 10; i++)
			{
				vBuffer[i] = _serial->read();
			}
			/* Flush exta bytes from receive buffer */
			while (_serial->available())
			{
				_serial->read();
			}
			/* Compute checksum from receive buffer and compare it to the computed checksum */
			checksum = checkSum(vBuffer);
			if (checksum == ((vBuffer[7]  << 8) || vBuffer[8]))
			{
				*retValue = ((vBuffer[5] << 8) || vBuffer[6]);
			}
			else
			{
				error = DFP_ERR_INV_CHK_SUM; 
			}
			/* Device returns an error data with this command */
			if (vBuffer[3] == 0x40)
			{
				error = DFP_ERR_DEV_ERROR;
			}
		}
		else
		{
			error = DFP_ERR_MIS_ANSWER; 
		}
	}
	return(error);
}

And next is the checksum function

/*
Compute check sum from a 10 bytes long buffer
*/
int16_t PlainDFP::checkSum(uint8_t *vBuffer)
{
	int16_t result = 0;
	for (uint8_t i = 1; i < 7; i++)
	{
		result += vBuffer[i];
	}
	result *= -1;
	return(result);
}

 

 

FN-M16P MP3 player (Part 1)

Part 1, 2

How come I managed to miss this fancy little module ? It’s my good ol’ friend Sébastien from Quai-Lab who showed me this little piece of electronic which he included in his inMoov robot. Bright idea ! For a few €, his robot will speak and improve its interactions to the public.

It did not take long before I found one on the Internet and got it delivered in a small envelop. Although this module is mostly known as the DF-Player Mini, it sounds like its original name is FN-M16P. This module is amazingly small, thanks to the use of Micro-SD card (aka TF card) on one side and two tiny ICs, one for the card management the other for amplifying the signal in order to directly connect a speaker to the module. A blue diode will light up when the module is playing songs.

I have not been able to find any link to the main chip which is marked as JC (maker ?) AA 1751CJ3MNP. Anybody has any hint ?

There are two ways of running this module: the autonomous way, and a driven way, requiring a simple MCU.

The autonomous way ranges from basic: next/previous track, +/- sound volume with only two buttons up to a 20 buttons interface wired as two banks of ten buttons each to the module !

The basic approach will be very helpful for checking your module. Next drawing illustrates the how to:

This is plain easy and does not even require any knowledge in electronics, except the understanding of VCC being the positive pole and GND the negative pole of a 3.2 … 5.0 V power supply.

Plugin the module to a MCU such as arduino is almost as easy. Next drawing illustrates the how to:

What is new to this design ? Firstly, there is no longer this basic human interface. The module is controlled by the MCU through a serial communication. Rx from one side connected to the opposite Tx. The two 1 kOhm resistors have been suggested by previous authors in order to attenuate the noise generated by the MCU and circulating through the communication lines. An ultimate solution would consist in using a level adapter as the the module is 3.3 V compliant, 5 V tolerant. In the same spirit, one may want to filter the power supply by adding a couple of capacitors, C1 ~tens of µF / 10 V and C2 0.1 µF / 10V. Also new is the use of the DAC outputs connected to any amplified speaker through a stereo line cord. This is the design that I used for testing and writing the related code.

Last but not least, here is a link to the data sheet. Although many copies or clones are available, most fail to provide accurate information. And this one is no even fully accurate, nor does it provide clear information… Some reverse engineering has been necessary to get deeper in the understanding, and while seeking for information I inadvertently found undocumented commands !

Next posts will relate to the code I wrote. But hey, stop ! Why bother writing code while it looks like many libraries exist ? Well the thing is that none from the three ones I downloaded worked from scratch and I found them pretty complex (in fact too much too complex) for plain applications. So that I decided to write a library my own way. As the documentation is not so good (compared to European standards), it took me sometime to get a clear picture of the available commands and the way they could be used.

I found that there are two ways (this is my analysis) of using this module: as a simple MP3 sound player or as a sound tracks manager. In my future writings, I will distinguish the notion of track (sound track) from the notion of folders and files.

A MP3 “sound player” will use the tracks oriented commands (playback, pause, stop, next, previous, repeat and random) while a “sound manager” application will randomly get named files in named directories (and still use pause, stop, next, previous, repeat options).  Also note that the module can read .wav files !

You do not to tidy or apply any naming convention to your file in the “sound player” mode. Copy up to 3000 tracks on a SD-Card and you’re done. For the “sound manager” mode, you have three options: store 65536 files in one special folder (named “MP3”), store up to 3000 files in 15 folders or store up to 255 files in 99 folders ! Each file must be preceded by its index. eg. 001-song_for_you.mp3, 002-song_for_me.mp3, … 255-song_for_them.mp3, in folders 01, 02 … 99. This is a glimpse at the principle of use and it may be helpful for thinking at applications such as a thermometer for the blind…

Next post on same subject

Shortage of Multilayer Ceramic Chip Capacitors (MLCC)

How come this tiny ultra familiar component is running out of stock ?

The information raised by constructors and vendors states that the unexpected growth of demand lead to a recurent shortage of products as explained here, there and here again. These papers also give advises for those who did not contract the supply of million of parts per month and who are bound to the availablity of detail suppliers (like I do!).

Ultimately, you may want to roll your own capacitors

 

PCBs (Part 4)

Part 1, 2, 3, 4

PCBWay order review

Delivery:

The parcel arrived in my mail box 5 days after the order date, as announced !!! This is great news as we are all eager to get the real thing asap.

Packing (Mail):

The parcel was delivered by DHL: we know this company, I personally used their services for China. As I was asking for adjusted fare rates depending on delivery times DHL told me that they have only one delivery mode: asap !

Content:

Here comes the smart part. We all know about the importance of the first seconds in a meeting, the first words and the first attitudes. PCBWay knows its job and surprise surprise, you get some nice goodies. Well done guys 😉

Packing (Product):

As expected, the PCBs are wrapped in a vacuum sealed plastic bag. This is state of the art.

PCB inspection:

Here are a couple of pictures taken with my modest means and my very limited skills at taking pictures:

And here is a closer look at the PCB

Conclusions:

What else can I say ? The pictures speak for them selves, delivery times are almost as short as delivery times for European based PCB companies. Taking into account the very moderate cost, this is a five star cost/quality option.

PCBs (Part 3)

Part 1, 2, 3, 4

Once we have our gerber files ready, it is time for “printing” the PCB. For a long time (and a long time ago) I used single sided coated copper Bakelite boards. Then I would copy the circuit  on copper using a special permanent ink pen (in negative) and immerse the board in a iron perchloride bath… Well, I understand that you could laugh at that, however, it was a quite standard manufacturing procedure in the so called “radio clubs” in the 70’s, and I recently heard that a mixing table (deluxe type, featuring 8 channels !) that I made in 1978 is still operating in a band!

After that came the time of circuits drawn with bitmap editors (once again, I understand that it sounds like prehistory) printed on transparent plastic sheet (at the time of the overhead projectors…) using my good ol’HP 4L laser printer which was perfect for the job. Then I used these printed slides in a custom made UV light box. After a revelation step, the PCB would be immersed in a more ecologic acid bath activated by air bubbles. Quite good results could be obtained, however the quality was very much dependent on the the quality of products: copper board (the insulation layer is aging), UV light tubes (aging too, requiring longer exposure times), acid bath (pH varies with temperature and engraving cycles), etc. In other words, this whole process was working fine with fresh products and for small series of PCBs but you could not expect reliable manufacturing for intermittent use.

An alternative consists in using a CNC machine to crave the PCBs resulting in typical engravings such as this example. I used to call this design style “à l’anglaise” but I could not find evidence of the correctness of this expression.

Thanks to advanced code and proper machining tools, most recent CNCs will produce very decent PCBs looking like “normal” ones such as the one produced next

Although this option looks interesting it suffers from few drawbacks which make the result of machined PCBs still look amateur. As the raw material is made of epoxy and copper, no plating will protect the pads, no coating will protect tracks and help soldering SMDs and no component labels or useful labeling shall be printed. In addition, track clearance may depend very much on the cutting tools and XY table resolution and tolerances.

The ultimate alternative is to subcontract the production of PCBs to one of the specialized companies. Most of them built their economical model on a highly automated process which enables the production of one to many boards in very short times. European companies benefit from quick delivery times while Asian companies offer low prices and decent delivery times. As a professional, I am frequent customer of BetaLayout, however, as a hobbyist I am looking for low cost suppliers offering reasonable delivery times and fares.

After a quick glance at the market lead me to PCBWay, a China Shenzhen-based PCB manufacturer which offers PCB making, board assembling operating under a streaming Quality Control (improperly advertised as Quality Assurance). PCBWay web site is clean and simple, using a lot of illustrations which come handy for setting the correct specifications and getting what you really want. This is very convenient for those who make an intermittent use of these services; early website were lacking such clarity and drove me to some disappointments and frustrations. Next is a screen capture of the parameter settings to be completed before getting the online quote.

The ordering process is fairly simple and lies on few stages:

Manufacturing tracking is available from PCBWay website while email are sent on each stage completion.

I have been used to receiving pictures of my own PCB while being manufactured which is very convenient for urgent orders: although these pictures may show frustrating flaws, it helps correcting them instantly and preparing a new order snappy. PCBWay may consider this option later on.

So far so good, I gave PCBWay a try and ordered the previously described PCB. The clock is now ticking and I am eager to share with you the results of this first run…

Next post on same subject

 

PCBs (Part 2)

Part 1, 2, 3, 4

Let’s exercise the tip and tricks that I shared with you in my latest post. Here are the requirements for this subject:

Project:

As a one idea per minute person, it was hard for me to stick to one project and one design. However, I had in mind the project of building an advanced Direct Digital Synthesizer  (DDS), some sort of an improved (much improved) version of some early projects. This prototype is a real proof of concept prototype. Instead of building it on a bread board, I decided to go for a PCB from scratch. Here are the three good reasons to do so:

  1. All sections from the circuit are well known or have been individually and successfully tested; the inverter is a charge pump thus creating no CEM troubles
  2. The mix of power supplies, digital and analog sections, the use of long component and wiring paths may create noisy signals and degrade the performances of the DDS
  3. PCB’s are getting cheaper and available quickly without the burden of making them yourself. We’ll get back to this point in the next posts.

Cad tool:

Kicad, version v4.0.7. Althought Kicad v5 is available, I decided to go for the stable version.

Components:

This project must contain a variety of sections (analog, digital, power supply) and components such as SMDs, through holes components, Non Plated Through Holes, headers. As this DDS will be driven by an Arduino UNO board, the PCB will have this unique shield shape.

Warnings:

This DDS features both digital and analog sections which tracks shall be separated. The power supply section features an inverter in order to allow -5 V to +5 V output signal swing thus requiring clean power supply “buses”. Care shall be taken to the position of headers and keepout areas (e.g. Arduino UNO USB connector).

PCB:

Next picture illustrates the components placement on the shield:

All active components are oriented in the same direction (pin 1 pointing the upper right corner of the board), same story for the polarized capacitors.

All components are regularly spaced and labelled as shown below

Next pictures illustrate the copper layers (Top and Bottom) of the shield:

On the top left are the DAC and digital potentiometers, all SPI, thus their location near PORTB. Beneath is the analog section that includes the operational amplifiers and below is the power supply section. The analog potentiometers and push buttons are located on the right and side.

Note: Although this DDS is planned to be digitally driven, I made provision for analog pots and push buttons in order to offer a dual user interface, both analog and digital. Under these conditions, analog pot positions shall be read and converted to digital for further frequency, amplitude and offset control.

From this picture, you can see that all tracks are shielded and kept as short as possible. Tests points are regrouped as much as possible (bottom left, upper left and upper mid area).

See how bottom tracks are arranged: power supply and analog signal tracks are almost all vertical in order to prevent a spaghetti PCB.

On the other hand, the SPI buses are horizontal. As shown in the picture below, the Chip Select lines from the SPI components are not isolated as they carry low frequency digital signals while the MOSI and CLK lines are isolated as they carry higher frequency signals.

A careful look at the tracks shows that the rule “one pad one track” is mostly respected. Vias are placed as far as possible from the pads in order to prevent thermal bridges as shown in the picture below.

Check also the presence of thermal reliefs for grounded pads. In this way, soldering is made easier and safer (for the components) as less heat must be applied to the pads in order to achieve the appropriate soldering temperature.

Last but not least, both copper sides feature large ground planes. Thanks to clean routing, and moderate components density, no copper-less islands were created thus no extra vias were needed.

If you need to pour copper in such island, this is how to create vias on Kicad: create a “via” module (typically plated through hole, inner diameter: 0.3 mm, outer ring diameter: 0.6 mm). Place the module at the convenient place (both sides at the same electrical potential). Right click on the pad, edit “Pad 1” (do not edit the entire module) and set the proper “Net name” (e.g. GND).

Note: Such vias will be flushed if you reload the Netfile using the “Delete” “extra footprints”. To prevent this, create a via component, add it to the schematics and link the component to the module.

Next post on same subject

 

PCBs (Part 1)

Part 1, 2, 3, 4

PCB design pitfalls… A quick glance on the net brought me to various interesting web sites:

“4 Circuit Board Design Mistakes to Avoid”
“PCB Design – The Top 5 Mistakes”
“6 PCB Design Mistakes to avoid designing printed circuit boards”
“7 Fatal Mistakes to Avoid on Your PCB Design”
“Top 9 mistakes that PCB engineers need avoid in PCB design”
“Top 10 PCB Routing Tips for Beginners”
“11 Myths About PCB Layout”

4, 5, 6, 7, 9, 10, 11 ? Is there really a limit to the number of PCB design pitfalls ? Probably not. From the very early times when I was using an ink pen to draw the tracks on plain copper before immersion in iron perchloride up to now, I had my glorious and my inglorious times which were more or less related to the success in making nice clean flawless PCBs.

So, based on my experiences, here is a list of reminders that I am sharing with you.

  • Footprints: Always get the components that you will solder on a PCB, check there dimensions, check your footprint libraries. Once routed, print the PCB copper layers and check the footprints. Personally, I am using my very own footprint libraries in order to avoid mastikes.
  • Not Plated Holes (NPTH): Unless your design is really screw-less, always provision holes for mounting your PCB on stands, posts or what so ever.
  • (Wire) Routing : If the copper layers look nice, the routing is probably fine. Spaghetti designs are almost always synonymous of trouble. Simplify and shorten routes. Check tracks width and maximize then when dealing with power supplies. Avoid routing tracks between pins.
  • Thermal relief: choose proper copper widths. Ban vias, plated holes, wide tracks located next to SMD pins. Avoid multiples tracks connect to a single pin.
  • Ground planes: Always ! However ground planes may have an impact on some components: use keep out areas if necessary. All tracks carrying weak signals must be buried.
  • Thermal vias: Although your prototype works great on the bench, the PCB may be used in harsh conditions and some components may insufficiently dissipate heat. Create thermal vias beneath power components and have sweet dreams.
  • Cuts: Did you check the overall dimensions of your PCB ? Check it again this way: print the PCB on plain paper, glue this page on cardboard, cut along the edges and try to adjust this mock PCB to its destination. Plain easy, plain beneficial.
  • Test points: Always ! Add test points to power supplies, critical signal points (inputs, outputs, driving pins, etc.). Whenever possible, group the test points in order to facilitate the work of the troubleshooter.
  • Silk prints: Always ! They are so usefull for identifying component references and orientations, test points, etc. Be strict while placing text, apply your own rules, e.g. on top or on the right. Always reference your PCB with a project name or code and above all with its revision name or code.
  • Wires: If you can, always tidy wires on one side. Don’t you ever connect wires here and there in the middle of nowhere. That’s rude.
  • Connectors: Less critical than wires however tidy connectors on the PCB edges, leave room around connectors so that clumsy fingers may be able to plug them.
  • Components: Use homogeneous component sizes. Try to orient polarized components in the same direction.
  • LEDs: So useful. LEDs are inexpensive and light indicators may save you a lot of time in the context of testing proof of concept prototypes. Feel free to get rid of the LEDs once all early tests pass.
  • Print geber files and analyze them individually. I am personally using a different software for designing PCB and for checking gerber files.
  • Check list: Build your own QC check list. Be strict, and whatever happens, even if your are in a hurry, use it: ultimately the time spent here will save you a great deal of time then ! If possible, ask someone else to counter check your works.
  • Backup: Once the gerber files is sent to the supplier, compress all related files and archive them (including libraries). Bringing corrections to the original files will drive you nuts. Create a “findings” file and a new version holding corrections.
  • Antennas: Think the PCB as a 3D environment ! Well, I think that if you are dealing with antennas you already know about the previous points of attention.

And now my very last advice: always leave one night in between your last final review and the upload of your gerber files to your favorite PCB maker. Most brains work hard during night, synthesizing thoughts and works so that, quite often in the morning, you may have an sparkling idea and get back in a hurry to one of those reminders that I tried to enumerate for you.

HTH

Next post on same subject

Current generators (Part 1)

Part 1

Here starts a new series of post dedicated to current generators. As usual, the idea is to describe working experimental prototypes that feature few components and quite good performances.

Current generators can be found in various applications such as battery chargers (advanced ones, aka multiple stages or intelligent battery chargers), LED drivers and all sorts of industrial applications such as 4-20 mA current loops.

Let’s start from the simplest up to more refined designs. Tweaking the LM317 voltage regulator is probably the simplest design. It requires only one very common chip and one adjustable resistor along with a couple of capacitors if high stability is required (optional components marked with a *).

Simplicity has a price, and in this case, the circuit suffers from few drawbacks: current adjustment is not linear versus the potentiometer cursor position as I = (1.25 / R), consequently it is tricky to adjust. However, thanks to additional fixed resistors, the adjustment range may be constrained and ease the fine tuning of current .

Next is a plot of the output from a current regulator where the feed back resistor is made of an adjustable one (150 Ohm) in parallel with a fixed one (1500 Ohm) to which is added an other resistor in serial (120 Ohm). This configuration results in an almost linear output ranging from 5 to 10 mA.

A better idea would consist in designing a more elaborate – although still simple circuit. The next one features an operational amplifier, a specialized chip used for measuring the voltage across a shunt resistor plus a few extra passive components. An INA193 chip (U2) is inserted in the feed back loop of the op-amp so that the voltage setting from the potentiometer (P1) is compared directly to the output voltage of the INA193 which is itself directly proportional to the current flowing through the shunt resistor (R shunt). The operational amplifier (U1) shall comply to the following characteristics: single supply power supply voltage, rail to rail input and output and output current compatible with the required output current of the circuit. I personally choose the MCP6001/2/4 which delivers up to 23 mA  and which I used a lot in recent designs.

Building the circuit is very easy as shown from the next picture

Next is an illustration of a simple spread-sheet (Open-Office format) that I built (as in many other designs) to play around with values. You may download it from >here<. I use color conventions for highlighting values of interest: orange for input values, gray for clones and yellow for output values.

It is possible to achieve higher output currents thanks to an additional transistor as show in the next schematic. This time, the current drawn is only limited by the transistor specifications: in the present case, the 2n3904 can drive up to 200 mA. However, care shall be taken with power dissipation, as this plastic package dissipates only 1.5 W.

 

I you lack the INA193 chip, you may build a differential amplifier of your own. Next is a suggested schematics for such current regulator.

It features a differential amplifier built around U2 which gain is determined by the R1/R2 and R3/R4 ratio (assuming R1=R3 and R2=R4). In this way the differential amplifier outputs a voltage which is equal to: G * the voltage drop across R shunt, where G is the gain. In order to achieve the proper amplification, resistors shall be from the precision class, 1% or better. R5 is a voltage limiter thus limiting the current output. Next is an illustration of the components set up on a breadboard.

 

 

 

Particle sensors (Part 1)

Part 1
I am amazed by the massive improvements of sensors along the last 10 years. Not so long ago, some sensors would fit in a shoe box and require 24 VDC, not to talk about the interfaces, weight, etc. These improvements are mainly due to the incorporation of advanced sensors in smart phones: camera, accelerometers, gyroscope, light sensors, gps, touch sensors, etc. Theses sensors come tiny, 3V, ULP, featuring digital interfaces and they come cheap too. Too bad for the pressure sensors, most industrial accelerometers: as there is no application yet for smart phone, the are still big, greedy, analog and expensive !

However, most sensor manufacturers try their best to offer new types of sensors. Some of them feature some well known components. The power of theses sensors lies in the embedded intelligence, the DSP inside which perform awesome calculations at high speeds. Among these sensors, I was intrigued by the particle sensor from Honeywell, namely the HPMA115S0-XXX, HPM Series Particle Sensor. I got one sample from Honeywell and gave this literally black box a try. The datasheet contains a very limited set of information, enough to make it run but probably insufficient for designing an industrial product.

The principle of operation is rather simple. A fan located on one exit of a S shaped channel creates a gentle air stream which carries particles. A light beam is directed across the air stream path while a photo-diode collects the photons. The signal of this photo-diode is computed locally my a MCU (FPGA ?) and outputs a serial signal on a UART port. This is how it looks really

Important: As the sensor features a fan, it requires a 5 VDC supply (<80 mA peak). However the UART port manages 3 V signals. Although the serial port is 5V tolerant, my advise is to use a bidirectional level translator such as this one:

Some code is available from Github, but, sorry, I did not like it. So I decided to rewrite it from scratch. Firstly, I decided to get rid of the continuous reading mode as it outputs large frames of mostly empty data. I understand that they made room for data that will be issued along with future development of the product. So far, I will skip this option. The code mainly consists in a command sender and a response reader. Both types of command are made flexible in order to match with commands requiring arguments or not as well as responses holding data or acknowledgment bytes. Next is the main command sender function. Use it for commands which require an argument.

/*
Send command with argument
*/
void sendCommand(uint8_t cmdType, uint8_t *vData, uint8_t dataSize)
{
	uint8_t vBytes[8];
	const uint8_t dataOffset = 3;
	/* Header in first place */
	vBytes[0] = 0x68; 
	/* Length in second place, equals (data size + 1) */
	vBytes[1] = (dataSize + 1);
	/* Command type in third place */
	vBytes[2] = cmdType;
	/* Data if any */
	for (uint8_t i = 0; i < dataSize; i++)
	{
		vBytes[dataOffset + i] = vData[i];
	}	
	/* Compute and record checksum */
	vBytes[dataOffset + dataSize] = checkSum(vBytes, (dataSize + 3));
	/* Send array of bytes */
	for (uint8_t i = 0; i < (dataSize + 4); i++)
	{
		mySerial.write(vBytes[i]);
	}
}

Each byte is buffered in order to compute the check sum according to their respective values. Next is the overloaded function that you will use for (most) commands which do not require an argument:

/*
Send command without argument
*/
void sendCommand(uint8_t cmdType)
{
	uint8_t *mock;
	sendCommand(cmdType, mock, 0);
}

Plain easy. Reading responses is a little bit more tricky as shown below

/*
Read response from device 
*/
bool readResponse(data_t *data)
{
	/* Set default response */
	bool res = false;
	/* Receiving buffer */
	uint8_t vBuffer[8];
	uint8_t ptr = 0; 
	/* Set default length to its maximum (data_size + 1) */
	uint8_t length = 5;
	uint8_t cmdType = 0;
	/* States */
	bool eofd = false;
	bool sofd = false;
	/* Read incoming bytes */
	if (mySerial.available())
	{
		while (mySerial.available())
		{
			/* Read and convert character */
			uint8_t readByte = (uint8_t)mySerial.read();
			if (!sofd)
			{
				switch (readByte)
				{
					case 0x40:
						/* Data header */
						sofd = true;
						break;
					case 0x96:
						/* Negative acknowledgment */
						sofd = true;
						eofd = true;
						res = false;
						break;
					case 0xA5:
						/* Positive acknowledgment */
						sofd = true;
						eofd = true;
						res = true;
						break;
				}
			}
			if (sofd && !eofd)
			{
				/* Record byte */
				vBuffer[ptr] = readByte; 	
				if (ptr == 1)
				/* Length in second place */
				{
					length = readByte;	
				}
				else if (ptr == 2)
				/* Command type in third place */
				{
					cmdType = readByte;
				}
				else if (ptr == (length + 2))
				/* End of frame */
				{
					eofd = true;							
					/* Check sum */
					if (vBuffer[length + 2] == checkSum(vBuffer, (length + 2)))
					{
						/* Compute data */
						switch (cmdType)
						{
							case cmdReadParticleMeasuringResults:
								data->pm_2_5 = ((uint16_t)vBuffer[3] << 8) | vBuffer[4];
								data->pm_10 = ((uint16_t)vBuffer[5] << 8) | vBuffer[6];	
								res = true;
								break;
							case cmdReadCustomerAdjustmentCoefficient:
								data->custAdjCoeff = ((uint16_t)vBuffer[3] << 8) | vBuffer[4];
								res = true;
								break;
						}
					}
				}
				/* Increment pointer */
				ptr += 1; 
			}
		}
	}
	/* Return result */
	return(res);
}

The function is built so that it will return a true state if every thing went right and vice versa. As the acknowledgment bytes are doubled, I simplified the code and check only the first incoming acknowledgment bytes (0xA5 = positive, 0x96 = negative). 0x40 is the first place announces data. All received bytes from a response containing data are buffered, once again for checking their sum. And here is the checksum function:

/* 
Compute the check sum from an array of bytes
the specified "bytes" number of bytes is used 
*/
uint8_t checkSum(uint8_t *vData, uint8_t bytes)
{
	/* Sum bytes */
	uint16_t sum = 0;
	for (uint8_t i = 0; i < bytes; i++)
	{
		sum += vData[i];
	}
	/* Compute the check sum */
	uint8_t check = uint8_t((0x10000 - sum) & 0xFF);
	/* Return checksum */
	return(check);
}

 

 

 

Metal detector (Part 1)

Dear cousin, I lost my keys in the middle of the meadows, would you please make a metal detector for me ? Urgent !

This is really how this project started ! More or less, as I have in mind the design of an Earth’s Field Nuclear Magnetic Resonance spectrometer which features magnetic fields sensors on which I already spent some time.

I started this metal detector project with a quick look at published projects on the web. Most, not to say all, projects feature a magnetic field sensor. The principle of operation consists in observing the changes in the magnetic permeability of the volume located on both sides apart a coil. There are multiple ways to implement this principle. One consists in emitting a magnetic pulse and measuring the strength of the echoed signal. The other consists in measuring the changes in frequency of a resonating tank. Both have their advantages and drawbacks. After few attempts, I decided to go for the second option which is far simpler in terms of mecatronics and electronics.

As mentioned above, the heart of the device is a resonating tank made of a coil and two capacitors. This configuration is known as the Collpits oscillator, named after its inventor Edwin H. Colpitts. The resonating frequency depends on the C1, C2 and L1 values, f = 1 / 2 . Pi . sqrt(L1. (C1 . C2) / (C1 + C2)).

Bipolar junction transistors, FET transistors or integrated op-amplifiers must be used to softly bias the oscillator and maintain a perpetual oscillation. I will use very popular small signal transistors such as the NPN 2N3904 or the 2N2222. For the passive components, I choose the following values: C1 = C2 = 10 nF and L1 = 600 µH, which results in a theoretical 92 kHz oscillating frequency. The reason for these choices lies in the capability of Arduino interrupts to cope with high frequencies. Staying close to 100 kHz was the objective and it proved to be alright. Various configurations exist and are described below:

First configuration:

C3 = 100 nF, R1 = R2 = 5 k, R3 = 1 k

Second configuration:

R1 = 100 k, R2 = 1 k, C3 = 10 nF

Third configuration:

C3 = 100 nF, R1 = R2 = 5 k, R3 = 1 k

Fourth configuration:

C3 = 1 nF, R1 = 470 k

Fith configuration:

C3 = 1 nF, C4 = 100 nF, R1 = R2 = 5 k, R3 = R4 = 1 k

As mentioned before, C1, C2 and L1 were chosen so that the resonating frequency is compatible with the sensing performances of the micro-controller. The use of lower frequencies will result in lower frequency shifts when a metallic object is present near the coil thus reducing the overall performances of the detector. I chose the first configuration which features a clean sine signal swinging from almost 0 V to almost 5 V.

The code is very straight forward in its basic version. Advanced users will add refinement for fine tuning the signal and taking into account frequency drifts caused by temperature mainly. It consists in sampling the number to cycles per second. The frequency stays idle at about 96 KHz and rises up to about 97 kHz when a metallic part enters the magnetic field.

volatile uint32_t pulse_counter; 
 
void setup(void) 
{ 
	/* Initialize the serial port */
	Serial.begin(38400); 
	/* Configure sensing pin (Digital pin 2)*/
	pinMode(2, INPUT); 
	attachInterrupt(0, count_pulse, RISING); 
} 
 
void loop(void) 
{ 
	/* Reset counter */
	pulse_counter = 0; 
	/* enable interrupts */
	interrupts(); 
	delay(1000); 
	/* disable interrupts */
	noInterrupts(); 
	/* Plot data */
	Serial.print(millis() / 1000.0, 1); 
	Serial.print(';'); 
	Serial.print(pulse_counter); 
	Serial.println(); 
} 
 
 /* Called when interrupted */
void count_pulse(void) 
{ 
	pulse_counter += 1; 
}

 

Time to use the metal detector… Well, it is not very sensitive however, it will do the job for finding keys fallen in the the grass.

Hello cousin ? No more worries, the keys were in my pocket ! Thanks anyway !

Well the followers of arduinoos will benefit from this quick and dirty project. Advanced users may decide to improve the design, starting from a the thermal stabilization of the oscillator as it is sensitive to temperature changes and drifts.