28317 Linescan Sensor Module
I want to interface the TSL 1401 -DB LINE SCAN SENSOR MODULE using the Propeller microcontroller.I used the datasheet of TSL1401R-LF and this is the code which I used.
CON
resolution = 256
_clkmode = xtal1 + pll16x
_clkfreq = 80_000_000
BASE_PIN=0
OBJ
pst : "Parallax Serial Terminal"
VAR
long Stack[16]
PUB main | i,value
DIRA[0..2]:=%110
pst.Start(115_200)
cognew(clk,@Stack)
pst.Str(String("Enter a decimal value: "))
repeat
OUTA[0]~~
waitcnt(clkfreq*0.0000001+cnt)
outa[0]~
repeat i from 1 to 128
value := INA[2]
pst.dec(value)
waitcnt(clkfreq*0.0000003232421875+cnt)
repeat i from 1 to 128
pst.dec(value)
PUB clk
repeat
outa[1]~~
waitcnt(clkfreq*0.000000125+cnt)
outa[1]~
waitcnt(clkfreq*0.000000125+cnt)
But it is displaying 83886097.Instead it should display binary values based on the intensity of light,So please help me in making this sensor to run correctly.
CON
resolution = 256
_clkmode = xtal1 + pll16x
_clkfreq = 80_000_000
BASE_PIN=0
OBJ
pst : "Parallax Serial Terminal"
VAR
long Stack[16]
PUB main | i,value
DIRA[0..2]:=%110
pst.Start(115_200)
cognew(clk,@Stack)
pst.Str(String("Enter a decimal value: "))
repeat
OUTA[0]~~
waitcnt(clkfreq*0.0000001+cnt)
outa[0]~
repeat i from 1 to 128
value := INA[2]
pst.dec(value)
waitcnt(clkfreq*0.0000003232421875+cnt)
repeat i from 1 to 128
pst.dec(value)
PUB clk
repeat
outa[1]~~
waitcnt(clkfreq*0.000000125+cnt)
outa[1]~
waitcnt(clkfreq*0.000000125+cnt)
But it is displaying 83886097.Instead it should display binary values based on the intensity of light,So please help me in making this sensor to run correctly.

Comments
Welcome to the forum!
Okay, first things first:
Please edit your post.
Also, I notice that you have four other threads started with the same question. I've had them deleted so we can focus on this one.
Regarding the obvious issues in your code:
2. But, more to the point, the waitcnts in your program are unnecessary and should be removed. Spin's overhead adds way more time than is needed by the sensor chip.
3. You're addressing value as an array, but it hasn't been declared as such. Declare value in the VAR section as an array, instead of as a local variable.
Which Propeller platform are you using with the TSL1401-DB? If it's the Propeller Backpack, I can upload a driver object for you that will simplify your programming.
-Phil
CON _clkmode = xtal1 + pll16x _clkfreq = 80_000_000 OBJ pst : "Parallax Serial Terminal" VAR long Stack[16] byte value[128] -----------[ Public Methods ]------------------------------------------------- PUB main | i DIRA[0..2]:=%110 pst.Start(115_200) cognew(clk,@Stack) repeat OUTA[0]~~ waitcnt(clkfreq/10000000+cnt) outa[0]~ repeat i from 1 to 128 value[i] := INA[2] pst.dec(value[i]) waitcnt(clkfreq/5988304+cnt) repeat i from 1 to 128 pst.dec(value[i]) PUB clk repeat outa[1]~~ waitcnt(clkfreq/8000000+cnt) outa[1]~ waitcnt(clkfreq/8000000+cnt)But the Parallax serial Terminal is not displaying anything.The clock frequency of the microcontroller is 80MHz and that which is required for this sensor is 8MHz.
I think,there is a problem with the synchronisation.I followed the timing Diagram of TSL1401-LF datasheet.
Change your waitcnt values to something larger. Such as:
Each of the very short waitcnt values you used will cause the Propeller to wait about 54 seconds as the 32-bit clock rolls over.
The smallest waitcnt valve is larger than 700 but smaller than 1000 (I don't recall the exact number).
So this would also work.
The above will wait for 12.5 us @ 80MHz (plus some extra time for code overhead).
Edit: It looks like you're trying to generate a very fast pulse. The easiest way to do this is with counters. There's a section in the Propeller Education Kit about counters that should help. The PEK can be found in the "help" menu of the Propeller Tool.
2. I would not include pst.dec(value) inside the read loop, since it will slow it down too much. You already have a separate loop after the azquisition loop. Just use that one to read out your data.
3. You have not made adequate provision for the exposure time. I would recommend a dummy acquisition loop, followed by a delay, before the actual acquisition loop. The exposure time would be the interval between pulsing SI.
Which board are you using with your Propeller chip?
-Phil
I also think your stack is too small, I make my stack 100 now at a minimum, because I have seen random issues with that as well.
I'm not sure exactly what you are trying to do, but I have had pst issues like this and learned what I'm telling you the hard way ... take this code with a grain of salt as untested (it will compile), but the format might help you.
CON _clkmode = xtal1 + pll16x _clkfreq = 80_000_000 OBJ pst : "Parallax Serial Terminal" VAR long Stack[100] long i byte value[128] '-----------[ Public Methods ]------------------------------------------------- PUB main | timeStamp, waitTime DIRA[0..2]:=%110 pst.Start(115_200) cognew(clk,@Stack) timeStamp := cnt waitTime := (clkfreq/10) repeat i from 1 to 128 pst.dec(value[i]) PUB clk | timeStamp, waitTime timeStamp := cnt waitTime := (clkfreq/10) repeat outa[1]~~ waitcnt(timeStamp += waitTime ) 'waitcnt(clkfreq/8000000+cnt) outa[1]~ waitcnt(timeStamp += waitTime ) 'waitcnt(clkfreq/8000000+cnt) PUB otherMethod | timeStamp, waitTime, waitTime2 timeStamp := cnt waitTime := (clkfreq/10) waitTime2 := (clkfreq/100) repeat OUTA[0]~~ waitcnt(timeStamp += waitTime ) outa[0]~ repeat i from 1 to 128 value[i] := INA[2] 'pst.dec(value[i]) ' This should be in the main method only, or a separate cog waitcnt(timeStamp += waitTime2 )Maybe you can describe in detail what you want to see as an output (or to monitor), and I can tweak my code to represent that better.
This code example polls 2 pins that I have LED's alternating on and off, and checks there states.
You'll see that I have 1 cog controlling the two pins alternation, and I have the first cog (main) monitoring it and updating the pst terminal window with the state. You can tweak this code so that the clk loop controls the light sensor, or updates a global variable with the light sensors state, and then the first cog (main) checks that global variable or pin and prints update values to the pst as fast as it can. The pst can only do a maximum of 115000 bits per second, so lets say that you only send the actual numerical value plus a carriage return, that's 3 bits plus a stop bit, so that's a theoretical maximum amount of 28800 updates to the pst per second.
Either way, if you have the data changing each microsecond, which is a million times a second, you can easily see that at absolute best, the pst could only theoretically catch 1 out of every 34.7 of the 1,000,000 updates per second. Make sense?
CON _clkmode = xtal1 + pll16x _clkfreq = 80_000_000 OBJ pst : "Parallax Serial Terminal" VAR long clkStack[100] PUB main | i, value, timeStamp, waitTime1, waitTime2, waitTime3 'DIRA[0..2]:=%110 i := 0 ' initialize your local variables to 0 value := 0 ' initialize your local variables to 0 waitTime1 := (clkfreq/2) ' this is a random delay that I chose for demonstration waitTime2 := (clkfreq/10) ' this is a random delay that I chose for demonstration waitTime3 := (clkfreq/100) ' this is a random delay that I chose for demonstration pst.Start(115_200) ' start your serial terminal object cognew(clk, @clkStack) ' assign your oscillation method to a new cog 'pst.Str(String("Enter a decimal value: ")) pst.Str(String("Starting ")) ' for sanitys sake when you are waiting for values to start appearing on the pst pst.Str(string(pst#NL)) ' a carriage return after printing something to the pst timeStamp := cnt ' sync a variable with the cnt, I always do this right before starting the loop repeat pst.Dec(ina[16]) ' print the state of the pin to the pst pst.Str(string(pst#NL)) ' a carriage return after printing something to the pst pst.Dec(ina[17]) ' print the state of the pin to the pst pst.Str(string(pst#NL)) ' a carriage return after printing something to the pst waitcnt(timeStamp += waitTime2) ' pause for whatever time delay, this may not be needed as the pst is slow { repeat 'i from 1 to 128 value[i] := INA[16] pst.dec(value[i]) waitcnt(timeStamp+waitTime2) value[i] := INA[17] pst.dec(value[i]) waitcnt(timeStamp+waitTime2) } { repeat i from 1 to 128 pst.dec(value[i]) } PUB clk | timeStamp, waitTime1, waitTime2, waitTime3 Dira[16]~~ ' initialize the pin direction Outa[16]~ ' initialize the pin state Dira[17]~~ ' initialize the pin direction Outa[17]~ ' initialize the pin state waitTime1 := (clkfreq/2) ' initialize local variables waitTime2 := (clkfreq/10) ' initialize local variables waitTime3 := (clkfreq/100) ' initialize local variables timeStamp := cnt ' sync a variable with the cnt, I always do this right before starting the loop repeat outa[16]~~ ' set pin high waitcnt(timeStamp += waitTime2) ' wait for a predetermined time between oscillations outa[16]~ ' set pin low waitcnt(timeStamp += waitTime2) ' wait for a predetermined time between oscillations outa[17]~~ ' set pin high waitcnt(timeStamp += waitTime2) ' wait for a predetermined time between oscillations outa[17]~ ' set pin low waitcnt(timeStamp += waitTime2) ' wait for a predetermined time between oscillations'':::::::[ TSL1401-DB Spin Driver ]:::::::::::::::::::::::::::::::::::::::::::: {{{ ┌───────────────────────────────────────┐ │ TSL1401-DB Driver writtin in Spin │ │(c) Copyright 2012 Bueno Systems, Inc. │ │ See end of file for terms of use. │ └───────────────────────────────────────┘ This program drives the TSL1401-DB completely from Spin. The sensor's analog output is thresholded against the Propeller's input logic threshold (nominally Vdd / 2) to produce either a 0 or a 1 for each pixel. The pixels are output continuously to the Parallax Serial Terminal in the form ....11111....11..., etc., where the 1's correspond to bright pixels, the periods to dark pixels. Each scan begins with a separate integration sequence to flush out pixels integrated during the output phase and to integrate over an accurate exposure time, given by EXPTIME (in usec). }} CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 'Define pine: AO = 0 'TSL1401 analog output. SI = 1 'TSL1401 start integrate and readout. CK = 2 'TSL1401 clock. 'Define exposure time (usec): EXPTIME = 16667 VAR byte pixels[128] 'Pixel array. OBJ sio : "Parallax Serial Terminal" PUB start | expticks, i sio.start(38400) 'Initialize serial output. dira[CK]~~ 'Set control pins as outputs. dira[SI]~~ expticks := clkfreq / 1000 * EXPTIME / 1000 'Convert exposure time to cnt ticks. frqa := frqVal(4_000_000) 'Set up frqa for 4 MHz clock burst. repeat waitcnt(i := cnt + 1000) 'Sync with cnt. ctra~ 'Dummy for same as following waitcnt. outa[SI]~~ 'Clock in SI pulse. outa[CK]~~ outa[SI]~ outa[CK]~ phsa~ 'Make sure burst starts with a low. ctra := %00100 << 26 | CK 'Start counter that outputs the burst on CK. waitcnt(i + expticks) 'Wait for exposure time to complete. ctra~ 'Turn off bursts. outa[SI]~~ 'Clock in SI pulse. outa[CK]~~ outa[SI]~ outa[CK]~ repeat i from 0 to 127 'Begin reading out 128 pixels (0 or 1). pixels[i] := ina[AO] ' Get pixel from input logic threshold on AO. outa[CK]~~ ' Pulse CK. outa[CK]~ sio.char(1) 'Move cursor to beginning of line. repeat i from 0 to 127 'Begin reading out 128 pixels. sio.char("." + pixels[i] * 3) ' Output "." for 0; "1" for 1. ''=======[ Tracy Allen's frqx Calculator ]===================================== PRI frqVal(freq) : frqx '' Return f = freq / clkfreq * 2^32, given freq < clrfreq, freq < 2^30 repeat 32 ' 32 bits freq <<= 1 frqx <<= 1 if freq => clkfreq freq -= clkfreq frqx++ ''=======[ License ]=========================================================== {{{ ┌──────────────────────────────────────────────────────────────────────────────────────┐ │ TERMS OF USE: MIT License │ ├──────────────────────────────────────────────────────────────────────────────────────┤ │Permission is hereby granted, free of charge, to any person obtaining a copy of this │ │software and associated documentation files (the "Software"), to deal in the Software │ │without restriction, including without limitation the rights to use, copy, modify, │ │merge, publish, distribute, sublicense, and/or sell copies of the Software, and to │ │permit persons to whom the Software is furnished to do so, subject to the following │ │conditions: │ │ │ │The above copyright notice and this permission notice shall be included in all copies │ │or substantial portions of the Software. │ │ │ │THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, │ │INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A │ │PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT │ │HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF │ │CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE │ │OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ └──────────────────────────────────────────────────────────────────────────────────────┘ }}Enjoy!
-Phil
-Phil
The 128 pixels scan is changing continuously changing with every press of the enter key.
What is the range of the sensor? and what about the focal length ?Is there an optimum focal length to achieve correct readings?
I actually want to calculate the width of an object using this sensor module and also the orientation of the object with respect to this sensor module.
I used a 3cm wide black strip on a white background for the experiments.Please help me out,to stabilise the readings of a fixed object and finally to find the width of the object.
-Phil
I am using a white paper with a BLACK STRIP OF 3CM WIDTH and observing the readings.
I want the object's orientation with respect to the sensor module
-Phil
Repeatability in the readings is not being achieved.
I have kept a black strip on a white background .
The black strip is exactly in front of the sensor module.
But 0s are being displayed in a corner.
It should display 11111111111111111110000000000011111111111111111
but sometimes it displays 111111111000011111111101101101111111111 and not in the exact position.
Please help me Sir in solving this problem.
BTW, which program are you using? The one I provided displays 11111111........11111111, not 111111110000000011111111. It may be that, in your situation, you need more than just a simple logic threshold to compare the pixel values to. You might consider a board with built-in sigma-delta ADC capabilities, such as the Propeller Backpack or even the QuickStart (which requires some soldering to activate ADC). With full ADC, you will be able to incorporate edge enhancement, which can compensate for effects such as vignetting and, to a lesser extent, variable lighting.
-Phil
[EDIT/]
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
AO = 15 ' Camera Analog Output
SI = 14 ' Camera SI
CLK = 13 ' Camera clock
LED = 3
OBJ
Sio : "FullDuplexSerialPlus"
Ls : "TSL1401Binary"
VAR '
byte image[128] ' image values
long exp ' exposure time in milli seconds
Pub Main | i
Initialize
exp := 100 ' exp milliseconds
repeat
Ls.LedOn
Ls.GetImage(@image, exp) ' Get an image
Ls.LedOff
Sio.tx(0)
Sio.str(@ruler1) ' Print rulers
Sio.tx(13)
Sio.str(@ruler2)
Sio.tx(13)
repeat i from 0 to 127
Sio.dec(image) ' Print image
Sio.tx(13)
Sio.tx(13)
Sio.dec(Ls.CountPixels(0, 127, Ls#DRK, @image)) ' Count dark
Sio.tx(9)
Sio.dec(Ls.CountPixels(0, 127, Ls#BRT, @image)) ' Count light
Sio.tx(13)
Sio.dec(LS.FindPixel(0, 127, LS#DRK, LS#FWD, @image)) ' Find dark pixel forward
Sio.tx(13)
Sio.dec(LS.FindEdge(0, 127, LS#LTOD, LS#FWD, @image)) ' Find light to dark edge forward
Sio.tx(9)
Sio.Dec(Ls.FindEdge(0, 127, LS#LTOD, LS#BKWD, @image)) ' Find light to dark edge backward
Sio.tx(13)
Sio.Dec(Ls.FindEdge(0, 127, LS#DTOL, LS#FWD, @image)) ' Find dark to light edge forward
Sio.tx(13)
i := LS.FindLine(0, 127, LS#DRK, LS#FWD, @image) ' Find dark line forward
Sio.Dec(i >> 16)
Sio.tx(9)
Sio.Dec((i & $FF00) >> 8)
Sio.tx(9)
Sio.Dec(i & $FF)
Sio.tx(13)
i := LS.FindLine(0, 127, LS#DRK, LS#BKWD, @image) ' Find dark line backward
Sio.Dec(i >> 16)
Sio.tx(9)
Sio.Dec((i & $FF00) >> 8)
Sio.tx(9)
Sio.Dec(i & $FF)
repeat until !Sio.rxcheck ' wait for key from terminal
PUB Initialize
{{ Initialize the pins direction and state. Must be called once. }}
Sio.start(31,30,0,115200) ' Rx,Tx, Mode, Baud
Ls.Init(AO, SI, CLK, LED)
DAT
ruler1 byte " 1 2 3 4 5 6 7 8 9 10 11 12", 0
ruler2 byte "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567", 0
{{
───────────────────────────────────────────┘
}}
[/EDIT]
Please edit your post, in order to preserve indentation. Also, you've said nothing so far about what kind of illumination you're using.
Thanks,
-Phil