linux screen tool for communication with microcontroller

Go To Last Post
62 posts / 0 new

Pages

Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, its raven again.

after compiling and uploading my source code into the microcontroller, i use [screen /dev/tty ACM0] command to summon the linux screen tool and carry out communication with the device. But the screen tool doesn't stay too long to complete the communication process as it times out quickly. Please anyone with an idea with what's wrong or a preferred soluton?

 

NB: ACM0 is the name of my microcontroller device when i use [ls /dev] command to check the list of devices connected to the pc

 

thanks immensely

Josh

Last Edited: Mon. Jul 8, 2019 - 07:08 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You shouldn't have a space between tty and ACM0.

 

You aren't explicitly setting the communication baud rate so are you sure the default baud rate is correct for your microcontroller? I briefly looked through the man page and couldn't find what the default buad rate is (I typically use minicom). Are you sure the data/parity/stop bit settings are consistent on both sides of the interface?

 

Finally, are you sure you have the correct permissions for accessing the serial device?

 

 

github.com/apcountryman/build-avr-gcc: a script for building avr-gcc

github.com/apcountryman/toolchain-avr-gcc: a CMake toolchain for cross compiling for the Atmel AVR family of microcontrollers

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The space between tty ACM0 is my mistake. Am sorry. Am new to xmega and I am trying to learn with this project. The screen tool is where for example ( I type in C and the device replies with # ) based on my progeam. The screen should stay longer but it disspaears before I can complete the sequence of characters. Do I have to check the baud rate of the microcontroller (atxmega 2563au) and the screen tool or what?

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just did a quick test where I attempted to execute screen without explicitly specifying the baud rate which resulted in screen terminating immediately with an error message of "[screen is terminating]". Everything worked fine when I did specify the baud rate (screen /dev/ttyACM0 115200 in my case). It looks like the default data/parity/stop bit configuration is 8-N-1 (not surprising).

 

Are you saying screen silently exits before you are able to perform/complete any actions?

github.com/apcountryman/build-avr-gcc: a script for building avr-gcc

github.com/apcountryman/toolchain-avr-gcc: a CMake toolchain for cross compiling for the Atmel AVR family of microcontrollers

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I get that same error back on the terminal after the screen disappears. It exits while still typing my command on it. I even had to type very quick to even get half way through the command sequence

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You are getting that because you didn't specify the baud rate. You should invoke screen as follows:

screen /dev/ttyACM0 <baud_rate>

where <baud_rate> is the baud rate you have configured your microcontroller to communicate at.

github.com/apcountryman/build-avr-gcc: a script for building avr-gcc

github.com/apcountryman/toolchain-avr-gcc: a CMake toolchain for cross compiling for the Atmel AVR family of microcontrollers

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

raven231996 wrote:
... or a preferred soluton?
pySerial

https://pythonhosted.org/pyserial/search.html?q=baud

pySerial examples has two terminals (miniterm.py, wxTerminal.py)

Examples — pySerial 3.0 documentation

 

"Dare to be naïve." - Buckminster Fuller

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you. I'll try this. Does that mean I have to keep adding the baud rate all the time I type that command line?

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes. If you don't like doing that there are other serial terminal programs (such as minicom) that have configurable defaults as well as savable configurations.

github.com/apcountryman/build-avr-gcc: a script for building avr-gcc

github.com/apcountryman/toolchain-avr-gcc: a CMake toolchain for cross compiling for the Atmel AVR family of microcontrollers

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you omit the baud rate, the default baud rate configured for that device will be used.  Usually it's 9600.

 

You can configure a tty device with stty, e.g.:

$ stty -F /dev/ttyACM0 115200 -ixon

... with set the baud, and disable XON/XOFF software flow control.  Often the default is for that to be enabled, which can cause trouble if you're using the device to transfer non-ASCII data.

 

You can see the current status of many parameters with:

$ stty -F /dev/ttyACM0

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OP says:

Does that mean I have to keep adding the baud rate all the time I type that command line?

No, use the capabilities of your shell.  Here's an alias I use to talk to a TI TM4C123 board:

alias tiva="cu -l /dev/tty.usbmodem0E214321 -s 115200"

It's in my .profile.

Yours will look something like: 

alias xmeg="screen /dev/ttyACM0 57600"

Add it to your .profile or .bash_profile or whatever you need for whatever shell you use, then make a new window and see that the new alias is there and works.

 

(The 'stty' could be helpful, but it doesn't last. You might need to redo the 'stty' command each time you plug in the board. Maybe every time it resets? Test and find out.)

 

Have fun!

Mike

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OP says:

Does that mean I have to keep adding the baud rate all the time I type that command line?

Eh! - What shell are you using that doesn't keep a command history ?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I use Putty (to install in ubuntu based distro-  sudo apt install putty). The advantage (or disadvantage) is you have gui access to the various features and can save 'sessions' (a particular port/speed/settings/etc.).

 

I also use 'stty' to set baud then 'cat' at a terminal when I just want to receive/watch data.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Another vote for minicom here. It's my terminal of choice in a Linux environment.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hi guys, just tried with the baud rate and still giving the same problem. am really confused. please, kindly help me with ideas

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

raven231996 wrote:
hi guys, just tried with the baud rate and still giving the same problem

 

just tried what precisley ?

If you're persisting with screen I would give up and use a modern alternative like minicom or miniterm.py (miniterm.py is installed alongside the pyserial module and is also multi-platform).

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

using putty, this is the error i get upon trying to type command 'EG'

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Open another terminal window, run -

dmesg -w

now try again and see if the usb device is disconnecting (you will see a message, and should be obvious if it disconnects)

 

If it is disconnecting, then any terminal app is not going to like that and will throw an error or exit. If so, then can troubleshoot the why.

Last Edited: Tue. Jul 9, 2019 - 11:49 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

After typing C, microcontroller responds with #
Next, I type k, microcontroller responds with #INFO: TWI master enabled
Next, I type !, microcontroller responds with C

after typing in the next command "EG", the screen gives that error. i have tried screen package on linux and it has the same issue

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

switch (command){
        case 'E': //Experiment options
            experiment_handler(getchar());
            break;
        
        case 'S': //Settings options
            settings_handler(getchar());
            break;
            
        case 'T': ;
            uint16_t tcs_data[] = {0,0,0,0};
            if (settings.settings.tcs_enabled == 0){
                printf("T-1.-1.-1.-1\n");
            }
            else {
                tcs_readvalues(tcs_data);
                printf("#INFO: TCS—%u %u %u %u\n", tcs_data[0], tcs_data[1], tcs_data[2], tcs_data[3]);
                printf("T%u.%u.%u.%u\n", tcs_data[0], tcs_data[1], tcs_data[2], tcs_data[3]);
            }
            break;

        case 'V': //check version
            #define STRING2(x) #x
            #define STRING(x) STRING2(x)
            #pragma message "GIT_COMMIT = " STRING(GIT_COMMIT)
            printf("V%u.%u.%u-%s\n", BOARD_VER_MAJOR, BOARD_VER_MINOR, BOARD_VER_MICRO, GIT_COMMIT);
            break;
        
        default:
            printf("#ERR: Command %c not recognized\n", command);
            return;
    }
    printf("no\n");
    return;
}

int main(void){
    
    board_init();
    pot_init();
    pmic_init();
    
    irq_initialize_vectors();
    cpu_irq_enable();
    sleepmgr_init();
    sysclk_init(); //Disables ALL peripheral clocks D:
    rtc_init();
    sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_EVSYS);
    
    pmic_set_scheduling(PMIC_SCH_ROUND_ROBIN);
    
    delay_ms(500);
    
    stdio_usb_init();
    stdio_usb_enable();
    
    ads1255_init_pins();
    ads1255_init_module();

    PORTD.INT0MASK = PIN5_bm;
    PORTD.INT1MASK = PIN5_bm;
    PORTD.INTCTRL = PORT_INT0LVL_OFF_gc | PORT_INT1LVL_OFF_gc;
    
    max5443_init_pins();
    max5443_init_module();
    
    ads1255_wakeup();
    ads1255_rdatac();
    ads1255_standby();
    
    ads1255_setup(ADS_BUFF_ON,ADS_DR_60,ADS_PGA_2);
    
    autogain_enable = 0;
    g_gain = POT_GAIN_30k;
    pot_set_gain();
    
    settings_read_eeprom();

    wdt_set_timeout_period(WDT_TIMEOUT_PERIOD_8KCLK); // 8 secs

    //    Wait for application connection - Get 'c', reply '#', get 'k'
    while(1){
        while(getchar() != 'c');
        putchar('#');
        while(getchar() != 'k');
        printf("\n\r");
        break;
    }

    tcs_init();
    wdt_enable();

    program_loop:
        while(getchar() != '!');
        printf ("C\n");
        command_handler(getchar());
        wdt_reset();
    goto program_loop;
}

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

    program_loop:
        while(getchar() != '!');
        printf ("C\n");
        command_handler(getchar());
        wdt_reset();
    goto program_loop;

 

So who is resetting the watchdog from the time it is setup to the time when the first wdt_reset() is run (unless you can get a terminal up and running and type fast, 8 seconds comes rather quickly). The dmesg -w command I showed, would tell you the usb is disconnecting, and a reset would certainly cause that.

Last Edited: Wed. Jul 10, 2019 - 12:12 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You think i should increase the watchdog timeout or what?

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What do you think you should do?

 

One option is to not enable the watchdog until you understand what it takes to keep it happy.

 

Another is to look at every while loop you have when wdt is enabled, and throw a wdt_reset() inside of it. You have one inside the main loop waiting for a '!'.

Last Edited: Wed. Jul 10, 2019 - 12:20 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

okay.

but it crashes majorly when i try to type in that "E" command at the beginning of the code i uploaded.

it majorly crashes when i try to type in E, S, T or V after typing in C, K and !

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How about just solving one problem first-

 

    //wdt_enable(); //do not enable watchdog (make sure fuses do not enable watchdog also, whatever mcu is in use)

    while(1){
        putchar( getchar() ); //echo what you type
    }

 

you should be able to type all day long at your terminal with the characters echoed back.

Once your terminal problem is solved, then conquer the next problem.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Alright. Thank you so much.
I'll give update on the result

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So I removed the wdt_reset & enable from the main.c and other source code they are in. Tested it with Linux screen package, it worked up to the point where I had to type the EG command. Note:the G command is in another.c

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
    program_loop:
        while(getchar() != '!');
        printf ("C\n");
        command_handler(getchar());
        wdt_reset();
    goto program_loop;

"goto" in 2019? Really? You do know that C is a structured language? Why not the more obvious:

    while (1) {
        while(getchar() != '!');
        printf ("C\n");
        command_handler(getchar());
        wdt_reset();
    }

Actually I see you know about while(1) already from the previous:

    while(1){
        while(getchar() != 'c');
        putchar('#');
        while(getchar() != 'k');
        printf("\n\r");
        break;
    }

but this too is a very curious piece of code. Why would you use a while(1) and then an unconditional break; from it? This code would have the same behaviour if you had simply written:

    while(getchar() != 'c');
    putchar('#');
    while(getchar() != 'k');
    printf("\n\r");

and forget the while/break all together.

 

Remember (as is happening here) you are often not the only one who has to read your code - try to make it as clear as possible for the next reader.

Last Edited: Wed. Jul 10, 2019 - 09:08 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So I removed the wdt_reset & enable from the main.c and other source code they are in. Tested it with Linux screen package, it worked up to the point where I had to type the EG command. Note:the G command is in another.c

Tested what. You seem to skipping over the part where we get to know if we are no longer troubleshooting a 'terminal' problem. Can you run the simple echo code I posted previously? Does the terminal app of choice work in that case? can you just type for a while and it keeps working? When you run dmesg -w in another terminal are you seeing the usb disconnect messages?

 

You would also gain the knowledge that the usb and uart code are probably ok, and that you have successfully disabled the watchdog.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I used putty this time around. And with the wdt enable gone, the terminal stays without crashing. I can now type for a while and it keeps working on putty.
If i see the usb disconnect message when I run dmesg-w does that mean the usb and uart code are okay?

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

>And with the wdt enable gone, the terminal stays without crashing

 

Ok, now everyone knows your terminal apps work, and you were dealing with a usb device (your mcu) that was disconnecting.

 

>If i see the usb disconnect message when I run dmesg-w does that mean the usb and uart code are okay?

 

The dmesg -w is simply to see when your particular device is disconnecting. You have nothing else in place to see when your mcu is resetting, so this is simply an indirect way to see an mcu reset. I would simply leave a terminal open with dmesg -w running so you get an idea of when your usb device is being connected or disconnected.

The echo test just mostly confirms that your usb code and uart code seem to be working (you would not see your usb device disconnect if it was working).

 

Now just figure out your next problem one simple step at a time. Follow the code where the trouble begins.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

alright. please what is the windows command alternative to dmesg -w

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The closest Windows gets to dmesg is the system events viewing log . But it's not really comparable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

alright. i'll try it with linux and give feedback. thank you so much guys. i am so grateful

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

>alright. please what is the windows command alternative to dmesg -w

 

The dinging sound when you plug/unplug a usb device.

 

This may work-

http://www.nirsoft.net/utils/usb_log_view.html

 

That fella has a lot of nice little Windows tools, which I have used for quite a long time.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thanks bro. please quick question

1. is the uart a visble chip on the Microcontroller board or inside the microcontroller chip itself?

2. what is the need for usart when there is already a uart?

3. is the max232 ic essential in a uart/usart-usb connection?

 

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Unless I missed it, I guess we don't know what you have so can't answer very well.

 

usart/uart- the same thing except one has an 's', which stands for synchronous. You are not using the 's', so with/without makes no difference. You are using the 'a' (if at all).

 

Its possible you are not using the uart at all, and you are simply talking to the usb in the mcu which pretends it is a uart. Your putchar/getchar/printf may all be going through the usb. You do have a usb_init function, so I gather you at least have usb on the mcu. If you had some other device like a serial-usb adapter, I guess you would not be seeing your terminal disconnect when the mcu resets. So probably disregard anything I said about uart, as you are probably not even using one.

 

>max232

If you are hooking up to a serial port on a pc (9 pin port, not very common anymore), then the serial port on the pc expects serial port voltages. Your mcu cannot produce them, so a max232 can take your small signals and make them serial port compatible. This would only be used when using an actual uart on the mcu (not usb), and you connected directly to the pc (not via a serial-to-usb adapter).

 

 

Last Edited: Wed. Jul 10, 2019 - 07:02 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

i asked the question just for general knowledge and not with respect to my present predicament. 

yea, my mcu board is connected via usb to pc. i uploaded a picture of the communication protocol from pc to microcontroller. i don't understand what you mean usb pretending to be uart

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

>i don't understand what you mean usb pretending to be uart

 

it acts like a uart- your mcu code is using functions like putchar/getchar/printf, your pc is using a terminal app like its talking to a uart. But there is no uart in use anywhere, even though the appearance is a uart is being used. Pretending.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

the microcontroller i am using is an atxmega256a3u which has a usart actually

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

>the microcontroller i am using is an atxmega256a3u which has a usart actually

 

so where is the uart being used? if not being used then 'no uart in use anywhere' would apply.

I wasn't trying to say you do not have a uart, just saying the usb is 'pretending' to be one. And doing a pretty good job of it, it seems.

 

here is a couple function calls you make in the code you have shown-

stdio_usb_init();
stdio_usb_enable();

 

I'm guessing the whole purpose of the 'stdio' part of that is to take over the whole group of stdio functions which typically go through the uart.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

alright

thank you

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

another challenge having now is that whenever i send the command EG, the microcontroller doesn't respond with what its meant to respond with (i.e  30k ) until i send ! again. once i send !,the 30k appears on the terminal. Is there a way i can the 30k can come out on its own without sending ! command again?

thank you

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Show your most recent code then.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

/*

* main.c

*

* Created: 29/09/2012 2:13:52 AM

* Author: mdryden

*/

 

#include "experiment.h"

#include "asf.h"

#include "wdt.h"

#include "settings.h"

#include "tcs.h"

#include <string.h>

#include <math.h>

#include <stdint.h>

 

//Internal function declarations

void command_handler(char command);

 

void command_handler(char command){

    /**

     * Deals with commands over USB

     *

     * Calls functions in

     * @param command Command character input.

     */

 

    switch (command){

case 'E': //Experiment options

experiment_handler(getchar());

break;

case 'S': //Settings options

settings_handler(getchar());

break;

case 'T': ;

uint16_t tcs_data[] = {0,0,0,0};

if (settings.settings.tcs_enabled == 0){

printf("T-1.-1.-1.-1\n");

}

else {

tcs_readvalues(tcs_data);

printf("#INFO: TCS—%u %u %u %u\n", tcs_data[0], tcs_data[1], tcs_data[2], tcs_data[3]);

printf("T%u.%u.%u.%u\n", tcs_data[0], tcs_data[1], tcs_data[2], tcs_data[3]);

}

break;

 

        case 'V': //check version

#define STRING2(x) #x

#define STRING(x) STRING2(x)

#pragma message "GIT_COMMIT = " STRING(GIT_COMMIT)

printf("V%u.%u.%u-%s\n", BOARD_VER_MAJOR, BOARD_VER_MINOR, BOARD_VER_MICRO, GIT_COMMIT);

            break;

        

        default:

            printf("#ERR: Command %c not recognized\n", command);

            return;

    }

    printf("no\n");

    return;

}

 

int main(void){

    

    board_init();

    pot_init();

    pmic_init();

    

    irq_initialize_vectors();

    cpu_irq_enable();

    sleepmgr_init();

    sysclk_init(); //Disables ALL peripheral clocks D:

    rtc_init();

    sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_EVSYS);

    

    pmic_set_scheduling(PMIC_SCH_ROUND_ROBIN);

    

    delay_ms(500);

    

    stdio_usb_init();

    stdio_usb_enable();

    

    ads1255_init_pins();

    ads1255_init_module();

 

    PORTD.INT0MASK = PIN5_bm;

    PORTD.INT1MASK = PIN5_bm;

    PORTD.INTCTRL = PORT_INT0LVL_OFF_gc | PORT_INT1LVL_OFF_gc;

    

    max5443_init_pins();

    max5443_init_module();

    

    ads1255_wakeup();

    ads1255_rdatac();

    ads1255_standby();

ads1255_setup(ADS_BUFF_ON,ADS_DR_60,ADS_PGA_2);

autogain_enable = 0;

g_gain = POT_GAIN_30k;

pot_set_gain();

settings_read_eeprom();

 

    //  Wait for application connection - Get 'c', reply '#', get 'k'

    while(1){

        while(getchar() != 'c');

        putchar('#');

        while(getchar() != 'k');

        printf("\n\r");

        break;

    }

 

    tcs_init();

    

    program_loop:

        while(getchar() != '!');

        printf ("C\n");

        command_handler(getchar());

    goto program_loop;

}

 

 

 

the intention is;

 i send via pc------microcontroller response

           c------------------#

           k------------------twi master enabled

           !------------------- c

           EG----------------- 30K

 

but instead i have to send ! again before the 30k appears on the terminal. NOTE: I BOLDED THE 30K COMMAND LINE IN THE CODE ABOVE SO YOU CAN EASILY TRACE IT

 

 

 

 

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Good to see you ignored previous comments I made. Ho Hum.

 k------------------twi master enabled

'k' handling itself does nothing more than print \r\n. I presume that when the call is made into the unseen tcs_init() that it's in there it prints "twi master enabled" (BTW can you really read orange on white??) 

  !------------------- c

Sorry to be pedantic but it is 'C' not 'c' - details like this DO matter.

EG----------------- 30K

We can see the processing of 'E':

case 'E'//Experiment options

experiment_handler(getchar());

break;

 

But where is the code for experiment_handler(). If the further processing of 'G' after 'E' is failing then surely it's within the experiment_handler() code you have not shown?

 

BTW your code is a total mess - apart from the bad choice of colour the indentation is all over the place so it is very hard to follow the sequence of operation.  If you use Atmel Studio 7 then on the Edit menu is "Edit-Advanced-Format Document". Suggest you use that. It results in:

/*
* main.c
*
* Created: 29/09/2012 2:13:52 AM
* Author: mdryden
*/

#include "experiment.h"
#include "asf.h"
#include "wdt.h"
#include "settings.h"
#include "tcs.h"
#include <string.h>
#include <math.h>
#include <stdint.h>

//Internal function declarations
void command_handler(char command);

void command_handler(char command){
	/**
	* Deals with commands over USB
	*
	* Calls functions in
	* @param command Command character input.
	*/
	
	switch (command){
		case 'E': //Experiment options
		experiment_handler(getchar());
		break;
		case 'S': //Settings options
		settings_handler(getchar());
		break;
		case 'T': ;
		uint16_t tcs_data[] = {0,0,0,0};
		if (settings.settings.tcs_enabled == 0){
			printf("T-1.-1.-1.-1\n");
		}
		else {
			tcs_readvalues(tcs_data);
			printf("#INFO: TCS—%u %u %u %u\n", tcs_data[0], tcs_data[1], tcs_data[2], tcs_data[3]);
			printf("T%u.%u.%u.%u\n", tcs_data[0], tcs_data[1], tcs_data[2], tcs_data[3]);
		}
		break;
		
		case 'V': //check version
		#define STRING2(x) #x
		#define STRING(x) STRING2(x)
		#pragma message "GIT_COMMIT = " STRING(GIT_COMMIT)
		printf("V%u.%u.%u-%s\n", BOARD_VER_MAJOR, BOARD_VER_MINOR, BOARD_VER_MICRO, GIT_COMMIT);
		break;
		
		default:
		printf("#ERR: Command %c not recognized\n", command);
		return;
	}
	printf("no\n");
	return;
}

int main(void){
	
	board_init();
	pot_init();
	pmic_init();
	
	irq_initialize_vectors();
	cpu_irq_enable();
	sleepmgr_init();
	sysclk_init(); //Disables ALL peripheral clocks D:
	rtc_init();
	sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_EVSYS);
	
	pmic_set_scheduling(PMIC_SCH_ROUND_ROBIN);
	
	delay_ms(500);
	
	stdio_usb_init();
	stdio_usb_enable();
	
	ads1255_init_pins();
	ads1255_init_module();
	
	PORTD.INT0MASK = PIN5_bm;
	PORTD.INT1MASK = PIN5_bm;
	PORTD.INTCTRL = PORT_INT0LVL_OFF_gc | PORT_INT1LVL_OFF_gc;
	
	max5443_init_pins();
	max5443_init_module();
	
	ads1255_wakeup();
	ads1255_rdatac();
	ads1255_standby();
	ads1255_setup(ADS_BUFF_ON,ADS_DR_60,ADS_PGA_2);
	autogain_enable = 0;
	g_gain = POT_GAIN_30k;
	pot_set_gain();
	settings_read_eeprom();
	
	//  Wait for application connection - Get 'c', reply '#', get 'k'
	while(1){
		while(getchar() != 'c');
		putchar('#');
		while(getchar() != 'k');
		printf("\n\r");
		break;
	}
	
	tcs_init();
	
	program_loop:
	while(getchar() != '!');
	printf ("C\n");
	command_handler(getchar());
	goto program_loop;
}

I hope you, like me, find that MUCH easier to read/follow?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

fyi- this looks like his starting point-

 

http://microfluidics.utoronto.ca/gitlab/dstat/dstat-firmware/tree/master/src

 

Not that it will help much.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

curtvm wrote:

fyi- this looks like his starting point-

 

http://microfluidics.utoronto.ca/gitlab/dstat/dstat-firmware/tree/master/src

 

Not that it will help much.

 

Its a remodification of his work

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

#include "experiment.h"

#include "settings.h"

#include "tcs.h"

#include "config/conf_board.h"

#include "wdt.h"

#include "asf.h"

 

//Public variable definitions

uint16_t g_gain = POT_GAIN_100;

uint16_t i_gain;

uint8_t g_short = 0;

uint8_t autogain_enable = 1;

 

//Private variables

volatile int32_t voltage = 0;

volatile uint16_t dacindex = 0;

volatile uint16_t iter = 0;

uint16_t* eis_ptr = 0;

volatile uint16_t cycles = 0;

volatile uint16_t samples = 0;

volatile uint16_t tcf0period = 0;

uint32_t skip_samples = 0;

 

uint16_t dacindex_stop = 0;

volatile int8_t up = 1;

 

volatile uint16_t supplied_voltage = 0;

volatile int32_t measured_current = 0;

volatile int16_t error = 0;

volatile int32_t g_current = 0;

volatile int32_t icorr_range_high = 0;

volatile int32_t icorr_range_low = 0;

volatile uint16_t passed = 0;

volatile uint16_t session = 0;

volatile uint16_t amount = 0;

 

//Private function declarations

static void porte_int0_lsv(void);

static void tcf0_ovf_callback(void);

static void tce1_ovf_callback_lsv(void);

static void lsv_cca_callback(void);

 

static void ca_cca_callback(void);

static void portd_int0_ca(void);

 

static void porte_int0_chr(void);

static void duration_rtc_callback(void);

static void interval_rtc_callback(void);

 

uint16_t set_timer_period(uint32_t period, volatile void *tc);

static void precond_rtc_callback(uint32_t time);

static uint8_t _swv_singledir(uint16_t dacindex, uint16_t dacindex_stop, uint16_t dacindex_pulse_height, uint16_t dacindex_step, uint8_t direction);

static uint8_t _dpv_singledir(uint16_t dacindex, uint16_t dacindex_stop, uint16_t dacindex_pulse_height, uint16_t dacindex_step, uint8_t direction);

 

//interrupt callback setup

typedef void (*port_callback_t) (void);

 

static port_callback_t portd_int0_callback;

 

void experiment_handler(char command){

static uint8_t p5, o1, o2, o3;

static int16_t p1, p2, p3;

static uint16_t u1, u2, u3, u4;

static int16_t pcv1, pcv2;

static uint16_t pct1, pct2;

static uint32_t cv;

static int32_t cc;

static uint32_t cd, ci;

uint16_t tcs_data[] = {0,0,0,0};

uint16_t tcs_data1[] = {0,0,0,0};

switch (command){

case 'A': //ADS Buffer/rate/PGA values from ads1255.h

scanf("%hhx%hhx%hhx",&o1,&o2,&o3);

printf("#A: %x %x %x\n",o1,o2,o3);

ads1255_setup(o1, o2, o3);

break;

case 'G': //Gain

scanf("%u%hhu",&g_gain, &g_short);

printf("#G: %u %u\n", g_gain, g_short);

pot_set_gain(); //uses global g_gain, so no params

break;

 

case 'I': //current limit

scanf("%u%hhu",&i_gain, &g_short);

printf("#G: %u %u\n", i_gain, g_short);

curr_set_switch(); //uses global I_gain, so no params

break;

 

case 'L': //LSV - start, stop, slope

scanf("%u%u%i%i%i%i%u",&pct1,&pct2,&pcv1,&pcv2,&p1,&p2,&u1);

printf("#L: %i %i %u\n",p1,p2,u1);

precond(pcv1,pct1,pcv2,pct2);

lsv_experiment(p1,p2,u1,2);

break;

 

case 'Q': // CHR - voltage, current, duration, interval

scanf("%lu%li%lu%lu",&cv,&cc,&cd,&ci);

            printf("#Q: %lu %li %lu %lu\n",cv,cc,cd,ci);

chronopot_experiment(cv,cc,cd,ci);

break;

#if BOARD_VER_MAJOR == 1 && BOARD_VER_MINOR >= 2

case 'P': //potentiometry - time, OCP/poteniometry

scanf("%u%hhu",&pct1, &o1);

printf("#P: %u %u\n",pct1,o1);

pot_experiment(pct1, o1);

break;

#endif

case 'C': //CV - v1, v2, start, scans, slope

scanf("%u%u%i%i%i%i%i%hhu%u",&pct1,&pct2,&pcv1,&pcv2,&p1,&p2,&p3,&p5,&u1);

precond(pcv1,pct1,pcv2,pct2);

cv_experiment(p1,p2,p3,p5,u1);

break;

case 'S': //SWV - start, stop, step size, pulse_height, frequency, scans

scanf("%u%u%i%i%i%i%u%u%u%u",&pct1,&pct2,&pcv1,&pcv2,&p1,&p2,&u1,&u2,&u3,&u4);

precond(pcv1,pct1,pcv2,pct2);

swv_experiment(p1,p2,u1,u2,u3,u4);

break;

case 'D': //DPV - start, stop, step size, pulse_height, period, width

scanf("%u%u%i%i%i%i%u%u%u%u",&pct1,&pct2,&pcv1,&pcv2,&p1,&p2,&u1,&u2,&u3,&u4);

precond(pcv1,pct1,pcv2,pct2);

dpv_experiment(p1,p2,u1,u2,u3,u4);

break;

case 'R': //CA - steps, step_dac[], step_seconds[]

scanf("%hhu",&p5); //get number of steps

printf("#INFO: Steps: %u\n\r", p5);

//allocate arrays for steps

uint16_t * step_dac = malloc(p5*sizeof(uint16_t));

uint16_t * step_seconds = malloc(p5*sizeof(uint16_t));

//check for successful allocation

if (!step_dac || !step_seconds){

printf("#ERR: Could not allocate memory\n\r");

break;

}

uint8_t i;

for (i=0; i<p5; i++){

scanf("%u", &step_dac[i]); // get voltage steps (dac units)

printf("#INFO: DAC: %u\n\r", step_dac[i]);

}

for (i=0; i<p5; i++){

scanf("%u", &step_seconds[i]); //get step durations (seconds)

printf("#INFO: Time: %u\n\r", step_seconds[i]);

}

scanf("%hhu", &o1);

printf("#INFO: TCS_check: %hhu\n\r", o1);

if (o1 > 0) {

if (settings.settings.tcs_enabled > 0){

tcs_readvalues(tcs_data);

delay_ms(25);

tcs_readvalues(tcs_data1); // If sensor disconnected, second measurement should be exactly the same

if (tcs_data[0] > settings.settings.tcs_clear_threshold){

printf("#ERR: Ambient light exceeds threshold %u\n\r", tcs_data[0]);

printf("#INFO: TCS—%u %u %u %u\n\r", tcs_data[0], tcs_data[1], tcs_data[2], tcs_data[3]);

return;

}

else if (tcs_data[3] == tcs_data1[3]){

printf("#ERR: Ambient light sensor seems to be disconnected \n\r");

return;

}

}

else {

printf("#ERR: Ambient light sensor disabled.\n\r");

return;

}

}

ca_experiment(p5, step_dac, step_seconds);

//free arrays

free(step_dac);

free(step_seconds);

break;

 

default:

printf("#ERR: Experiment command %c not recognized\n", command);

wdt_reset();

}

}

 

/* CHR */

uint8_t chronopot_experiment(uint32_t voltage, int32_t current, uint32_t duration, uint32_t interval) {

/**

* Perform a chronopotentiometry experiment

*

* @param voltage Start voltage in mV.

* @param current Protection current of the system in A.

* @param duration Duration to run experiment if abort is not received in s.

* @param interval Interval to report output in s.

*/

uint8_t ret = 0; // Return status - 0 (normal return), 1 (aborted)

    uint16_t tol = 50; // Tolerance

icorr_range_high = current + tol;

icorr_range_low = current - tol;

g_current = current;

supplied_voltage = (uint16_t) voltage; //global voltage

    session = interval; // global interval

 

if (duration <= interval) {

printf("#WAR: Duration <= interval\n");

printf("#CHR: Running for one interval\n");

        duration = interval; // Run for 1 duration

    }

    

amount = ceil((double)duration / interval); // calculate the amount of intervals in duration

max5443_set_voltage1(supplied_voltage); // supply digital voltage

 

// Configure RTC

while (RTC.STATUS & RTC_SYNCBUSY_bm);

RTC.PER = 65535;

while (RTC.STATUS & RTC_SYNCBUSY_bm);

RTC.CTRL = RTC_PRESCALER_DIV1024_gc; //1s tick

rtc_set_callback((rtc_callback_t)interval_rtc_callback);

 

    volt_exp_start(); // connect experiment pins

ads1255_wakeup();

    ads1255_rdatac(); // continuous data read mode

ads1255_sync();

portd_int0_callback = porte_int0_chr; // ADC read

rtc_set_alarm(interval); // set interval alarm interrupt

 

RTC.CNT = 1;

PORTD.INTCTRL = PORT_INT0LVL_MED_gc; //ADC read

 

printf("#CHR: P=%03u A=%03u | V=%lu I=%li\n",passed,amount,voltage,current);

// Run experiment with interrupts

up = 1;

while (up) {

//Abort handling

if (udi_cdc_is_rx_ready()){

if (getchar() == 'a'){

duration_rtc_callback();

ret = 1;

printf("##ABORT\n");

goto aborting;

}

}

}

 

aborting:

RTC.CTRL = RTC_PRESCALER_OFF_gc;

RTC.INTCTRL = RTC_COMPINTLVL_OFF_gc;

PORTD.INTCTRL = PORT_INT0LVL_OFF_gc;

volt_exp_stop();

ads1255_standby();

passed = 0x0; session = 0x0;

return ret;

}

 

static void porte_int0_chr(void){

/**

* ISR for taking CHR measurements.

*/

measured_current = ads1255_read_fast24(); //read current

bool in_range = measured_current > icorr_range_low && measured_current < icorr_range_high;

int16_t volts = (int16_t) supplied_voltage;

if (!in_range) {

error = ceil((100/(double)g_current) * (g_current - measured_current));

volts -= error;

supplied_voltage = (uint16_t) volts;

max5443_set_voltage1(supplied_voltage);

}

else if (in_range && measured_current > (g_current + 10)) {

// reduce current by increasing voltagebit

supplied_voltage += (uint16_t) 1; // decrement by 0.5mV

max5443_set_voltage1(supplied_voltage);

}

else if (in_range && measured_current < (g_current - 10)) {

// increase current by reducing voltagebit

supplied_voltage -= (uint16_t) 1; // increment by 0.5mV

max5443_set_voltage1(supplied_voltage);

}

 

wdt_reset();

 

return;

}

 

static void duration_rtc_callback(void) {

    up = 0;

    RTC.CTRL = RTC_PRESCALER_OFF_gc;

    RTC.INTCTRL = RTC_COMPINTLVL_OFF_gc;

PORTD.INTCTRL = PORT_INT0LVL_OFF_gc;

printf("#CHR: Duration interrupt called\n");

}

 

static void interval_rtc_callback(void) {

    /*

* ISR for reporting data

*/

    passed++;

 

struct {

uint16_t voltage;

int32_t current;

} data;

// define data

data.voltage = supplied_voltage; // private variable

data.current = measured_current; // private variable

 

// Reset RTC

    if (passed >= amount) {

        up = 0;

        return;

    }

    else {

        rtc_set_alarm(session);

        RTC.CNT = 1;

    }

 

// send

    printf("B\n");

    udi_cdc_write_buf(&data, 6);

    printf("\n");

/* debug */

printf("#DBG: %%E=%i\n",error);

printf("#CII: P=%03u A=%03u | V=%u I=%li\n",passed,amount,data.voltage,data.current);

printf("\n");

/* debug */

 

    return;

}

/* End */

 

/* LSV */

uint8_t lsv_experiment(int16_t start, int16_t stop, uint16_t slope, int8_t first_run){

/**

* Perform a LSV experiment.

*

* Uses porte_int0_lsv to output to USB.

* @param start Start potential in mV.

* @param stop Stop potential in mV.

* @param slope Scan rate in mV/s.

* @param first_run Keeps track of number of scans so potentiostat isn't initialized twice or disconnected when doing CV. Set to 2 for normal LSV.

*/

uint8_t ret = 0;

//check experiment limits

if(start<-1500 || start>=1500 ||start==stop|| stop<-1500 || stop>=1500 || slope>7000)

{

printf("#ERR: Experiment parameters outside limits\n");

return ret;

}

uint16_t dacindex_start = ceil(start*(65536/(double)2500)+32768);

dacindex_stop = ceil(stop*(65536/(double)2500)+32768);

uint32_t timer_period;

uint16_t temp_div;

max5443_set_voltage1(dacindex_start);

if (first_run == 1 || first_run == 2){

volt_exp_start();

ads1255_rdatac();

tc_enable(&TCC1);

ads1255_sync();

tc_enable(&TCC0);

tc_set_overflow_interrupt_callback(&TCC0, tcf0_ovf_callback);

tc_set_overflow_interrupt_callback(&TCC1, tce1_ovf_callback_lsv);

tc_set_cca_interrupt_callback(&TCC1, lsv_cca_callback);

portd_int0_callback = porte_int0_lsv; //ADC read

//set EVCH0 event

EVSYS.CH0MUX = EVSYS_CHMUX_TCC0_OVF_gc;

EVSYS.CH0CTRL = 0;

timer_period = ceil(1/((double)slope/(2500./65536))*(F_CPU));

temp_div = ceil(timer_period/65536.);

if (temp_div <= 1)

tc_write_clock_source(&TCC0,TC_CLKSEL_DIV1_gc);

else if (temp_div == 2){

tc_write_clock_source(&TCC0,TC_CLKSEL_DIV2_gc);

timer_period /= 2;

}

else if (temp_div <= 4){

tc_write_clock_source(&TCC0,TC_CLKSEL_DIV4_gc);

timer_period /= 4;

}

else if (temp_div <= 8){

tc_write_clock_source(&TCC0,TC_CLKSEL_DIV8_gc);

timer_period /= 8;

}

else if (temp_div <= 64){

tc_write_clock_source(&TCC0,TC_CLKSEL_DIV64_gc);

timer_period /= 64;

}

else if (temp_div <= 256){

tc_write_clock_source(&TCC0,TC_CLKSEL_DIV256_gc);

timer_period /= 256;

}

else if (temp_div <= 1024){

tc_write_clock_source(&TCC0,TC_CLKSEL_DIV1024_gc);

timer_period /= 1024;

}

else{

printf("ERR: Frequency/ADC rate is too low\n");

return ret;

}

ads1255_wakeup();

tc_write_period(&TCC1, 0xffff);

tc_write_period(&TCC0, (uint16_t)timer_period);

}

TCC1.CNT = dacindex_start;

if (stop > start)

{

up = 1;

tc_set_direction(&TCC1, TC_UP);

}

else

{

up = -1;

tc_set_direction(&TCC1, TC_DOWN);

}

tc_write_cc(&TCC1, TC_CCA, dacindex_stop);

tc_enable_cc_channels(&TCC1, TC_CCAEN);

TCC0.CNT = 0;

tc_set_cca_interrupt_level(&TCC1, TC_INT_LVL_HI); //Stop experiment

tc_set_overflow_interrupt_level(&TCC0, TC_OVFINTLVL_LO_gc); //Set DAC

PORTD.INTCTRL = PORT_INT0LVL_MED_gc; //ADC read

tc_write_clock_source(&TCC1, TC_CLKSEL_EVCH0_gc);

//Experiment run with interrupts

while (up != 0){

if (udi_cdc_is_rx_ready()){

if (getchar()=='a'){

tce1_ovf_callback_lsv();

ret = 1;

goto aborting;

}

}

}

if (first_run == -1 || first_run == 2)

{

aborting:

tc_disable(&TCC0);

TCC0.CNT = 0x0;

tc_disable(&TCC1);

volt_exp_stop();

ads1255_standby();

return ret;

}

return ret;

}

 

static void porte_int0_lsv(void){

/**

* ISR for taking LSV measurements.

*/

struct {

uint16_t index;

int32_t result;

} data;

data.result = ads1255_read_fast24();

static uint16_t last_value = 0;

uint32_t current = TCC1.CNT;

data.index = (current+last_value)>>1; //DAC value is average of current and last timer - approximation of center of averaging window

printf("B\n");

udi_cdc_write_buf(&data, 6);

last_value = (uint16_t)current;

printf("\n");

wdt_reset();

return;

}

 

static void tcf0_ovf_callback(void){

max5443_set_voltage1(TCC1.CNT);

}

 

static void tce1_ovf_callback_lsv(void){

PORTD.INTCTRL = PORT_INT0LVL_OFF_gc;

tc_set_overflow_interrupt_level(&TCC0, TC_OVFINTLVL_OFF_gc);

tc_set_overflow_interrupt_level(&TCC1, TC_OVFINTLVL_OFF_gc);

up = 0;

return;

}

 

static void lsv_cca_callback(void){

PORTD.INTCTRL = PORT_INT0LVL_OFF_gc;

tc_set_overflow_interrupt_level(&TCC0, TC_OVFINTLVL_OFF_gc);

tc_set_cca_interrupt_level(&TCC1, TC_INT_LVL_OFF);

up = 0;

return;

}

/* End */

 

/* POT */

#if BOARD_VER_MAJOR == 1 && BOARD_VER_MINOR >= 2

void pot_experiment(uint16_t time_seconds, uint8_t exp_type){

/**

* Performs a potentiometry experiment.

*

* @param time_seconds Time until automatic stop. If 0, can only be canceled by abort signal.

* @param exp_type Type of experiment, POT_OCP for OCP, POT_POTENT for potentiometry

*/

while (RTC.STATUS & RTC_SYNCBUSY_bm);

RTC.PER = 999;

while (RTC.STATUS & RTC_SYNCBUSY_bm);

RTC.CTRL = RTC_PRESCALER_DIV1_gc; //1ms tick

RTC.CNT = 0;

EVSYS.CH0MUX = EVSYS_CHMUX_RTC_OVF_gc; //EV CH0 -- RTC overflow 1s

portd_int0_callback = portd_int0_ca; //ADC interrupt

tc_enable(&TCC0);

ads1255_mux(ADS_MUX_POT);

ads1255_rdatac();

ads1255_wakeup();

tc_write_period(&TCC0,0xffff);

tc_write_clock_source(&TCC0, TC_CLKSEL_EVCH0_gc);

tc_set_direction(&TCC0, TC_UP);

up = 1;

if (time_seconds >= 1){ //only enable interrupt if non-zero timeout specified

tc_set_cca_interrupt_callback(&TCC0, ca_cca_callback);

tc_write_cc(&TCC0, TC_CCA, time_seconds-1);

tc_enable_cc_channels(&TCC0, TC_CCAEN);

tc_clear_cc_interrupt(&TCC0, TC_CCA);

tc_set_cca_interrupt_level(&TCC0, TC_INT_LVL_MED);

}

if (exp_type == POT_OCP)

{

ocp_exp_start();

}

RTC.CNT=0;

PORTD.INTCTRL = PORT_INT0LVL_LO_gc;

TCC0.CNT = 0;

while (up !=0){

if (udi_cdc_is_rx_ready()){

if (getchar() == 'a'){

ca_cca_callback();

printf("##ABORT\n");

goto aborting;

}

}

}

aborting:

tc_set_cca_interrupt_level(&TCC0, TC_INT_LVL_OFF);

tc_write_clock_source(&TCC0, TC_CLKSEL_OFF_gc);

tc_disable(&TCC0);

volt_exp_stop();

ads1255_standby();

return;

}

#endif

 

static void portd_int0_ca(void){

struct {

uint16_t time1;

uint16_t time2;

int32_t current;

} data;

data.time1 = TCC0.CNT;

data.time2 = RTC.CNT;

data.current = ads1255_read_fast24();

printf("B\n");

udi_cdc_write_buf(&data, 8);

printf("\n");

wdt_reset();

}

 

static void ca_cca_callback(void){

/**

* Interrupt handler for CA. Triggers when counter matches CC to stop potential step.

*

*/

PORTD.INTCTRL = PORT_INT0LVL_OFF_gc;

up = 0;

return;

}

/* End */

 

void pot_init(void){

/**

* Initializes AVR port directions and levels

*

* @return Nothing.

*/

#if BOARD_VER_MAJOR == 1 && BOARD_VER_MINOR == 1

ioport_set_port_dir(IOPORT_PORTB, PIN3_bm|PIN4_bm|PIN5_bm|PIN6_bm|PIN7_bm, IOPORT_DIR_OUTPUT);

ioport_set_port_dir(IOPORT_PORTD, PIN4_bm, IOPORT_DIR_OUTPUT);

ioport_set_port_level(IOPORT_PORTB, PIN3_bm|PIN4_bm|PIN5_bm|PIN6_bm|PIN7_bm, PIN3_bm|PIN6_bm|PIN7_bm);

ioport_set_port_level(IOPORT_PORTD, PIN4_bm, PIN4_bm);

#endif

#if BOARD_VER_MAJOR == 1 && BOARD_VER_MINOR == 3

ioport_set_port_dir(IOPORT_PORTB, PIN2_bm|PIN3_bm|PIN4_bm|PIN5_bm|PIN6_bm|PIN7_bm, IOPORT_DIR_OUTPUT);

ioport_set_port_dir(IOPORT_PORTD, PIN4_bm, IOPORT_DIR_OUTPUT);

ioport_set_port_dir(IOPORT_PORTF, PIN0_bm|PIN1_bm|PIN2_bm|PIN3_bm|PIN4_bm|PIN5_bm|PIN6_bm, IOPORT_DIR_OUTPUT);

ioport_set_port_level(IOPORT_PORTB, PIN2_bm|PIN3_bm|PIN4_bm|PIN5_bm|PIN6_bm|PIN7_bm, PIN3_bm|PIN6_bm|PIN7_bm);

ioport_set_port_level(IOPORT_PORTD, PIN4_bm, PIN4_bm);

#endif

}

 

void curr_set_switch(void){

//POT_GAIN_0:

ioport_set_port_level(IOPORT_PORTB, PIN6_bm|PIN7_bm, PIN7_bm);

ioport_set_port_level(IOPORT_PORTD, PIN4_bm, PIN4_bm);

 

scanf("%u",&i_gain);

 

switch (i_gain) {

case CURR_SET_10M:

ioport_set_port_level(IOPORT_PORTF, PIN6_bm, 1);

printf("#INFO: 10M\n");

break;

case CURR_SET_1M:

ioport_set_port_level(IOPORT_PORTF, PIN5_bm, 1);

printf("#INFO: 1M\n");

break;

case CURR_SET_100k:

ioport_set_port_level(IOPORT_PORTF, PIN4_bm, 1);

printf("#INFO: 100k\n");

break;

case CURR_SET_10k:

ioport_set_port_level(IOPORT_PORTF, PIN3_bm, 1);

printf("#INFO: 10K\n");

break;

case CURR_SET_1k:

ioport_set_port_level(IOPORT_PORTF, PIN2_bm, 1);

printf("#INFO: 1K\n");

break;

case CURR_SET_100:

ioport_set_port_level(IOPORT_PORTF, PIN1_bm, 1);

printf("#INFO: 100\n");

break;

case CURR_SET_10:

ioport_set_port_level(IOPORT_PORTF, PIN0_bm, 1);

printf("#INFO: 10\n");

break;

default:

printf("#WAR: Invalid curr gain.\n");

break;

return;

}

}

 

void pot_set_gain(void){

/**

* Sets iV gain according to current g_gain value

*

* @return Nothing.

*/

switch (g_gain){

#if BOARD_VER_MAJOR == 1 && BOARD_VER_MINOR == 1

case POT_GAIN_500M:

ioport_set_port_level(IOPORT_PORTB, PIN6_bm|PIN7_bm, 0);

ioport_set_port_level(IOPORT_PORTD, PIN4_bm, 0);

printf("#INFO: 500M\n");

break;

case POT_GAIN_30M:

ioport_set_port_level(IOPORT_PORTB, PIN6_bm|PIN7_bm, PIN6_bm);

ioport_set_port_level(IOPORT_PORTD, PIN4_bm, 0);

printf("#INFO: 30M\n");

break;

case POT_GAIN_3M:

ioport_set_port_level(IOPORT_PORTB, PIN6_bm|PIN7_bm, PIN7_bm);

ioport_set_port_level(IOPORT_PORTD, PIN4_bm, 0);

printf("#INFO: 3M\n");

break;

case POT_GAIN_300k:

ioport_set_port_level(IOPORT_PORTB, PIN6_bm|PIN7_bm, PIN6_bm|PIN7_bm);

ioport_set_port_level(IOPORT_PORTD, PIN4_bm, 0);

printf("#INFO: 300k\n");

break;

case POT_GAIN_30k:

ioport_set_port_level(IOPORT_PORTB, PIN6_bm|PIN7_bm, 0);

ioport_set_port_level(IOPORT_PORTD, PIN4_bm, PIN4_bm);

printf("#INFO: 30k\n");

break;

case POT_GAIN_3k:

ioport_set_port_level(IOPORT_PORTB, PIN6_bm|PIN7_bm, PIN6_bm);

ioport_set_port_level(IOPORT_PORTD, PIN4_bm, PIN4_bm);

printf("#INFO: 3k\n");

break;

case POT_GAIN_300:

ioport_set_port_level(IOPORT_PORTB, PIN6_bm|PIN7_bm, PIN7_bm);

ioport_set_port_level(IOPORT_PORTD, PIN4_bm, PIN4_bm);

printf("#INFO: 300\n");

break;

case POT_GAIN_100:

ioport_set_port_level(IOPORT_PORTB, PIN6_bm|PIN7_bm, PIN6_bm|PIN7_bm);

ioport_set_port_level(IOPORT_PORTD, PIN4_bm, PIN4_bm);

printf("#INFO: 100\n");

break;

#endif

#if BOARD_VER_MAJOR == 1 && BOARD_VER_MINOR == 3

case POT_GAIN_100M:

ioport_set_port_level(IOPORT_PORTB, PIN6_bm|PIN7_bm, 0);

ioport_set_port_level(IOPORT_PORTD, PIN4_bm, 0);

printf("#INFO: 100M\n");

break;

case POT_GAIN_30M:

ioport_set_port_level(IOPORT_PORTB, PIN6_bm|PIN7_bm, PIN6_bm);

ioport_set_port_level(IOPORT_PORTD, PIN4_bm, 0);

printf("#INFO: 30M\n");

break;

case POT_GAIN_3M:

ioport_set_port_level(IOPORT_PORTB, PIN6_bm|PIN7_bm, PIN7_bm);

ioport_set_port_level(IOPORT_PORTD, PIN4_bm, 0);

printf("#INFO: 3M\n");

break;

case POT_GAIN_300k:

ioport_set_port_level(IOPORT_PORTB, PIN6_bm|PIN7_bm, PIN6_bm|PIN7_bm);

ioport_set_port_level(IOPORT_PORTD, PIN4_bm, 0);

printf("#INFO: 300k\n");

break;

case POT_GAIN_30k:

ioport_set_port_level(IOPORT_PORTB, PIN6_bm|PIN7_bm, 0);

ioport_set_port_level(IOPORT_PORTD, PIN4_bm, PIN4_bm);

printf("#INFO: 30k\n");

break;

case POT_GAIN_3k:

ioport_set_port_level(IOPORT_PORTB, PIN6_bm|PIN7_bm, PIN6_bm);

ioport_set_port_level(IOPORT_PORTD, PIN4_bm, PIN4_bm);

printf("#INFO: 3k\n");

break;

case POT_GAIN_0:

ioport_set_port_level(IOPORT_PORTB, PIN6_bm|PIN7_bm, PIN7_bm);

ioport_set_port_level(IOPORT_PORTD, PIN4_bm, PIN4_bm);

printf("#INFO: 0\n");

break;

case POT_GAIN_100:

ioport_set_port_level(IOPORT_PORTB, PIN6_bm|PIN7_bm, PIN6_bm|PIN7_bm);

ioport_set_port_level(IOPORT_PORTD, PIN4_bm, PIN4_bm);

printf("#INFO: 100\n");

break;

default:

printf("#WAR: Invalid pot gain.\n");

break;

return;

#endif

}

}

 

void volt_exp_start(void){

    /**

     * Connects measurement cell to rest of circuit.

     */

    #if BOARD_VER_MAJOR == 1 && BOARD_VER_MINOR == 1

        ioport_set_port_level(IOPORT_PORTB, PIN3_bm|PIN4_bm|PIN5_bm, PIN3_bm|PIN4_bm);

    #endif

 

    

#if BOARD_VER_MAJOR == 1 && BOARD_VER_MINOR == 3

if (g_gain <= 7)

{

ioport_set_port_level(IOPORT_PORTB, PIN2_bm|PIN3_bm|PIN4_bm|PIN5_bm, PIN2_bm|PIN4_bm);

}

else

{

ioport_set_port_level(IOPORT_PORTB, PIN6_bm|PIN7_bm, PIN7_bm);

ioport_set_port_level(IOPORT_PORTD, PIN4_bm, PIN4_bm);

ioport_set_port_level(IOPORT_PORTB, PIN2_bm, 1);

}

    #endif

delay_ms(100); // Make sure WE circuit is connected before control voltage applied

ioport_set_pin_level(PIN_POT_CE, 1);

    

if (g_short == 1)

ioport_set_pin_level(PIN_POT_2ELECTRODE, 1);

else

ioport_set_pin_level(PIN_POT_2ELECTRODE, 0);

}

 

void volt_exp_stop(void){

    /**

     * Disconnects measurement cell.

     */

    #if BOARD_VER_MAJOR == 1 && BOARD_VER_MINOR == 1

        ioport_set_port_level(IOPORT_PORTB, PIN3_bm|PIN5_bm, 0);

    #endif

    #if BOARD_VER_MAJOR == 1 && BOARD_VER_MINOR == 3

        ioport_set_port_level(IOPORT_PORTB, PIN2_bm|PIN3_bm|PIN5_bm, 0);

    #endif

delay_ms(100); // Make sure WE is last to disconnect

ioport_set_pin_level(PIN_POT_WE, 0);

ioport_set_pin_level(PIN_POT_2ELECTRODE, 1);

}

 

#if BOARD_VER_MAJOR == 1 && BOARD_VER_MINOR >= 2

void ocp_exp_start(void){

    if (g_gain <=7)

     ioport_set_port_level(IOPORT_PORTB, PIN2_bm|PIN3_bm|PIN4_bm|PIN5_bm, PIN4_bm);

else

ioport_set_port_level(IOPORT_PORTB, PIN6_bm|PIN7_bm, PIN7_bm);

ioport_set_port_level(IOPORT_PORTD, PIN4_bm, PIN4_bm);

ioport_set_port_level(IOPORT_PORTB, PIN2_bm|PIN3_bm|PIN5_bm, 0);

ioport_set_port_level(IOPORT_PORTF, 0X7F, IOPORT_PIN_LEVEL_HIGH);

}

#endif

 

/* Extra */

uint16_t set_timer_period(uint32_t period, volatile void *tc) {

/**

* Sets a suitable timer source and sets period for a 16-bit timer

*

* @param period 32-bit period in CPU cycles

* @param *tc pointer to timer to set

* @return divider used.

*/

uint16_t temp_div = ceil((double)period/65536);

uint16_t divider = 0;

if (temp_div == 1)

tc_write_clock_source(tc, TC_CLKSEL_DIV1_gc);

else if (temp_div == 2){

tc_write_clock_source(tc, TC_CLKSEL_DIV2_gc);

divider = 2;

}

else if (temp_div <= 4){

tc_write_clock_source(tc, TC_CLKSEL_DIV4_gc);

divider = 4;

}

else if (temp_div <= 8){

tc_write_clock_source(tc,TC_CLKSEL_DIV8_gc);

divider = 8;

}

else if (temp_div <= 64){

tc_write_clock_source(tc,TC_CLKSEL_DIV64_gc);

divider = 64;

}

else if (temp_div <= 256){

tc_write_clock_source(tc,TC_CLKSEL_DIV256_gc);

divider = 256;

}

else if (temp_div <= 1024){

tc_write_clock_source(tc,TC_CLKSEL_DIV1024_gc);

divider = 1024;

}

else{

printf("#Frequency/ADC rate is too low\n\r");

return 0;

}

period /= divider;

tc_write_period(tc, (uint16_t)period);

return divider;

}

 

void precond(int16_t v1, uint16_t t1, int16_t v2, uint16_t t2) { //assumes potentiostat switches are already set

/**

* Performs experiment preconditioning.

*

* @param v1 First potential (DAC index).

* @param t1 First duration (s).

* @param v2 Second potential (DAC index).

* @param t2 Second duration (s).

*/

uint16_t time_old = 0;

while (RTC.STATUS & RTC_SYNCBUSY_bm);

RTC.PER = 65535;

while (RTC.STATUS & RTC_SYNCBUSY_bm);

RTC.CTRL = RTC_PRESCALER_DIV1024_gc; //1s tick

rtc_set_callback((rtc_callback_t)precond_rtc_callback);

up = 1;

//first potential

if (t1 > 0){

max5443_set_voltage1(v1);

rtc_set_alarm(t1);

RTC.CNT = 0;

volt_exp_start();

while (up){

if (udi_cdc_is_rx_ready()){

if (getchar() == 'a'){

precond_rtc_callback(t1);

printf("##ABORT\n\r");

goto aborting;

}

}

if (time_old != RTC.CNT){

time_old = RTC.CNT;

printf("#%u\n\r",time_old);

}

}

}

up = 1;

time_old = 0;

if (t2 > 0){

max5443_set_voltage1(v2);

rtc_set_alarm(t2);

RTC.CNT = 0;

volt_exp_start();

while (up){

if (udi_cdc_is_rx_ready()){

if (getchar() == 'a'){

precond_rtc_callback(t2);

printf("##ABORT\n\r");

goto aborting;

}

}

if (time_old != RTC.CNT){

time_old = RTC.CNT;

printf("#%u\n\r",time_old);

}

}

}

aborting:

volt_exp_stop();

return;

}

static void precond_rtc_callback(uint32_t time) {

up = 0;

RTC.INTCTRL |= RTC_COMPINTLVL_OFF_gc;

}

 

void cv_experiment(int16_t v1, int16_t v2, int16_t start, uint8_t scans, uint16_t slope) {

/**

* Perform a CV experiment.

*

* Calls lsv_experiment several times to make a CV experiment.

* @param v1 Vertex 1 in mV.

* @param v2 Vertex 2 in mV.

* @param start Start voltage in mV.

* @param scans Number of scans.

* @param slope Scan rate in mV/s.

*/

// check if start is [v1,v2]

int8_t firstrun = 1;

if((start < v1 && start < v2) || (start > v1 && start > v2)){

printf("#ERR: Start must be within [v1, v2]\n\r");

return;

}

while(scans > 0){

if (start != v1){

if (lsv_experiment(start,v1,slope,firstrun) == 1)

return;

firstrun = 0;

}

if (start == v2 && scans == 1)

firstrun = -1;

if (lsv_experiment(v1,v2,slope,firstrun) == 1)

return;

if (scans == 1)

firstrun = -1;

if (start != v2)

if(lsv_experiment(v2,start,slope,firstrun) == 1)

return;

--scans;

firstrun = 0;

printf("S\n\r"); //signal end of scan

}

printf("D\n\r"); //signal end of experiment

return;

}

 

void ca_experiment(uint16_t steps, uint16_t step_dac[], uint16_t step_seconds[]) {

/**

* Performs a chronoamperometry experiment.

*

* @param steps Total number of steps.

* @param step_dac[] Array containing DAC indices.

* @param step_seconds[] Array containing step durations in seconds.

*/

while (RTC.STATUS & RTC_SYNCBUSY_bm);

RTC.PER = 999;

while (RTC.STATUS & RTC_SYNCBUSY_bm);

RTC.CTRL = RTC_PRESCALER_DIV1_gc; //1ms tick

RTC.CNT = 0;

EVSYS.CH0MUX = EVSYS_CHMUX_RTC_OVF_gc; //EV CH0 -- RTC overflow 1s

portd_int0_callback = portd_int0_ca; //ADC interrupt

tc_enable(&TCC0);

tc_set_cca_interrupt_callback(&TCC0, ca_cca_callback);

ads1255_rdatac();

ads1255_wakeup();

tc_write_period(&TCC0,0xffff);

tc_write_clock_source(&TCC0, TC_CLKSEL_EVCH0_gc);

tc_set_direction(&TCC0, TC_UP);

tc_enable_cc_channels(&TCC0, TC_CCAEN);

tc_set_cca_interrupt_level(&TCC0, TC_INT_LVL_MED);

TCC0.CNT = 0;

max5443_set_voltage1(step_dac[0]);

volt_exp_start();

for (uint8_t i = 0; i < steps; ++i) {

up = 1;

tc_write_cc(&TCC0, TC_CCA, TCC0.CNT+step_seconds[i]-1);

RTC.CNT=0;

max5443_set_voltage1(step_dac[i]);

printf("#DAC: %u\n\r", step_dac[i]);

PORTD.INTCTRL = PORT_INT0LVL_LO_gc;

while (up !=0){

if (udi_cdc_is_rx_ready()){

if (getchar() == 'a'){

ca_cca_callback();

printf("##ABORT\n\r");

goto aborting;

}

}

}

}

aborting:

tc_set_cca_interrupt_level(&TCC0, TC_INT_LVL_OFF);

tc_write_clock_source(&TCC0, TC_CLKSEL_OFF_gc);

tc_disable(&TCC0);

volt_exp_stop();

ads1255_standby();

return;

}

 

void swv_experiment(int16_t start, int16_t stop, uint16_t step, uint16_t pulse_height, uint16_t frequency, uint16_t scans) {

/**

* Perform a SWV experiment

*

* @param start Start voltage in mV.

* @param stop Stop voltage in mV.

* @param step Step voltage in mV.

* @param pulse_height Pulse amplitude in mV.

* @param frequency Frequency in Hz.

* @param scans Number of scans (0 for single direction mode)

*/

uint8_t direction;

uint16_t dacindex_start = ceil((start)*(65536/(double)3000))+32768;

uint16_t dacindex_stop = ceil(stop*(65536/(double)3000))+32768;

uint16_t dacindex_step = ceil(step*(65536/(double)3000));

uint16_t dacindex_pulse_height = ceil(pulse_height*(65536/(double)3000));

uint32_t period;

if (start < stop)

direction = 1;

else

direction = 0;

tc_enable(&TCF0);

tc_enable(&TCC0);

frequency *= 2; //compensate for half-period triggers

//calculate time to ADC trigger

period = ceil((1/(double)frequency)*F_CPU);

uint32_t adc_period = ceil(((1/(double)frequency)-(double)(sample_delay_ms_100div/1e5))*F_CPU);

set_timer_period(period, &TCF0);

set_timer_period(adc_period, &TCC0);

ads1255_wakeup();

ads1255_standby();

volt_exp_start();

do{

TCF0.CNT = 0;

TCC0.CNT = 0;

if (_swv_singledir(dacindex_start, dacindex_stop, dacindex_pulse_height, dacindex_step, direction))

goto aborting; //function will return non-zero if abort called over USB

if (scans > 0){ //non-cyclic mode skips out after one direction

TCF0.CNT = 0;

TCC0.CNT = 0;

if (_swv_singledir(dacindex_stop, dacindex_start, dacindex_pulse_height, dacindex_step, !direction)) //swap start and stop and invert direction for second half of scan

goto aborting;

}

printf("S\n\r"); //signal end of scan

} while (scans-- > 1); //will underflow after comparison for scans = 0 , but shouldn't matter

printf("D\n\r"); //signal end of experiment

aborting:

volt_exp_stop();

tc_write_clock_source(&TCF0, TC_CLKSEL_OFF_gc);

tc_disable(&TCF0);

TCF0.CNT = 0;

tc_write_clock_source(&TCC0, TC_CLKSEL_OFF_gc);

tc_disable(&TCC0);

TCC0.CNT = 0;

ads1255_standby();

return;

}

 

uint8_t _swv_singledir (uint16_t dacindex, uint16_t dacindex_stop, uint16_t dacindex_pulse_height, uint16_t dacindex_step, uint8_t direction) {

/**

* Internal function that performs a single direction sweep for SWV

*

* @param dacindex Starting voltage as dac index

* @param dacindex_stop Stop voltage in dac index.

* @param dacindex_step Step voltage in dac index.

* @param dacindex_pulse_height Pulse amplitude in dac index.

* @param direction Scan direction - 1 for up, 0 for down.

*/

int32_t forward = 0;

int32_t reverse = 0;

uint16_t lastindex = 0;

if (direction == 1)

max5443_set_voltage1(dacindex+dacindex_pulse_height);

else

max5443_set_voltage1(dacindex-dacindex_pulse_height);

while ((dacindex <= dacindex_stop && direction == 1) || (dacindex >= dacindex_stop && direction == 0)){

tc_clear_overflow(&TCF0);

tc_clear_overflow(&TCC0);

while (!tc_is_overflow(&TCC0)){ //ADC tc overflow

if (udi_cdc_is_rx_ready()){ //check for abort signal over USB

if (getchar() == 'a')

return 1;

}

}

ads1255_wakeup();

while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTD, 5)));

forward = ads1255_read_single24();

ads1255_standby();

while (!tc_is_overflow(&TCF0)); //wait for end of half-cycle

TCC0.CNT = 0;

if (direction == 1) //switch voltage to other half of cycle

max5443_set_voltage1(dacindex-dacindex_pulse_height);

else

max5443_set_voltage1(dacindex+dacindex_pulse_height);

tc_clear_overflow(&TCF0); //reset timer OVF

tc_clear_overflow(&TCC0);

while (!tc_is_overflow(&TCC0)){ //ADC tc overflow

if (udi_cdc_is_rx_ready()){ //check for abort signal over USB

if (getchar() == 'a')

return 1;

}

}

ads1255_wakeup();

while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTD, 5)));

reverse = ads1255_read_single24();

ads1255_standby();

while (!tc_is_overflow(&TCF0)); //wait for end of half-cycle

TCC0.CNT = 0;

lastindex = dacindex;

//increment dacindex

if (direction == 1){

dacindex += dacindex_step;

max5443_set_voltage1(dacindex+dacindex_pulse_height);

}

else{

dacindex -= dacindex_step;

max5443_set_voltage1(dacindex-dacindex_pulse_height);

}

//data output

struct {

uint16_t lastindex;

int32_t forward;

int32_t reverse;

} data;

data.lastindex = lastindex;

data.forward = forward;

data.reverse = reverse;

printf("B\n");

udi_cdc_write_buf(&data, 10);

printf("\n");

}

return 0;

}

 

void dpv_experiment(int16_t start, int16_t stop, uint16_t step, uint16_t pulse_height, uint16_t pulse_period, uint16_t pulse_width) {

/**

* Perform a DPV experiment

*

* @param start Start voltage in mV.

* @param stop Stop voltage in mV.

* @param step Step voltage in mV.

* @param pulse_height Pulse amplitude in mV.

* @param pulse_period Pulse period in ms.

* @param pulse_width Pulse width in ms.

*/

uint8_t direction;

uint16_t dacindex_start = ceil((start)*(65536/(double)3000))+32768;

uint16_t dacindex_stop = ceil(stop*(65536/(double)3000))+32768;

uint16_t dacindex_step = ceil(step*(65536/(double)3000));

uint16_t dacindex_pulse_height = ceil(pulse_height*(65536/(double)3000));

uint32_t cpu_period;

uint32_t cpu_width;

if (start < stop)

direction = 1;

else

direction = 0;

tc_enable(&TCF0);

tc_enable(&TCC0);

//calculate time to ADC trigger

cpu_period = ceil((double)pulse_period*1e-3*F_CPU);

uint32_t adc_period = ceil((((double)pulse_period*1e-3)-(double)(sample_delay_ms_100div/1e5))*F_CPU);

uint16_t divider = set_timer_period(cpu_period, &TCF0);

uint16_t adc_divider = set_timer_period(adc_period, &TCC0);

cpu_width = (double)pulse_width*1e-3*F_CPU;

uint32_t adc_width = ceil((((double)pulse_width*1e-3)-(double)(sample_delay_ms_100div/1e5))*F_CPU);

tc_write_cc(&TCF0, TC_CCA, (uint16_t)(cpu_width/divider));

tc_enable_cc_channels(&TCF0, TC_CCAEN);

tc_write_cc(&TCC0, TC_CCA, (uint16_t)(adc_width/adc_divider));

tc_enable_cc_channels(&TCC0, TC_CCAEN);

ads1255_wakeup();

ads1255_standby();

volt_exp_start();

TCF0.CNT = 0;

TCC0.CNT = 0;

if (_dpv_singledir(dacindex_start, dacindex_stop, dacindex_pulse_height, dacindex_step, direction))

goto aborting; //function will return non-zero if abort called over USB

printf("D\n\r"); //signal end of experiment

aborting:

volt_exp_stop();

tc_write_clock_source(&TCF0, TC_CLKSEL_OFF_gc);

tc_disable(&TCF0);

tc_write_clock_source(&TCC0, TC_CLKSEL_OFF_gc);

tc_disable(&TCC0);

TCF0.CNT = 0;

TCC0.CNT = 0;

ads1255_standby();

return;

}

 

uint8_t _dpv_singledir (uint16_t dacindex, uint16_t dacindex_stop, uint16_t dacindex_pulse_height, uint16_t dacindex_step, uint8_t direction) {

/**

* Internal function that performs a single direction sweep for DPV

*

* @param dacindex Starting voltage as dac index

* @param dacindex_stop Stop voltage in dac index.

* @param dacindex_step Step voltage in dac index.

* @param dacindex_pulse_height Pulse amplitude in dac index.

* @param direction Scan direction - 1 for up, 0 for down.

*/

int32_t forward = 0;

int32_t reverse = 0;

uint16_t lastindex = 0;

if (direction == 1)

max5443_set_voltage1(dacindex+dacindex_pulse_height);

else

max5443_set_voltage1(dacindex-dacindex_pulse_height);

while ((dacindex <= dacindex_stop && direction == 1) || (dacindex >= dacindex_stop && direction == 0)){

tc_clear_overflow(&TCF0);

tc_clear_cc_interrupt(&TCF0, TC_CCA);

tc_clear_overflow(&TCC0);

tc_clear_cc_interrupt(&TCC0, TC_CCA);

while (!tc_is_cc_interrupt(&TCC0, TC_CCA)){ //wait until ADC TC CCA match

if (udi_cdc_is_rx_ready()){ //check for abort signal over USB

if (getchar() == 'a')

return 1;

}

}

ads1255_wakeup();

while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTD, 5)));

forward = ads1255_read_single24();

ads1255_standby();

while (!tc_is_cc_interrupt(&TCF0, TC_CCA)); //wait for end of half-cycle

//switch voltage to baseline

max5443_set_voltage1(dacindex);

while (!tc_is_overflow(&TCC0)){ //wait for ADC TC overflow

if (udi_cdc_is_rx_ready()){

if (getchar() == 'a')

return 1;

}

}

ads1255_wakeup();

while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTD, 5)));

reverse = ads1255_read_single24();

ads1255_standby();

while (!tc_is_overflow(&TCF0)); //wait for end of half-cycle

TCC0.CNT = 0; // Resync ADC TC

lastindex = dacindex;

//increment dacindex

if (direction == 1){

dacindex += dacindex_step;

max5443_set_voltage1(dacindex+dacindex_pulse_height);

}

else{

dacindex -= dacindex_step;

max5443_set_voltage1(dacindex-dacindex_pulse_height);

}

//data output

struct {

uint16_t lastindex;

int32_t forward;

int32_t reverse;

} data;

data.lastindex = lastindex;

data.forward = forward;

data.reverse = reverse;

printf("B\n");

udi_cdc_write_buf(&data, 10);

printf("\n");

}

return 0;

}

/* Extra */

 

ISR(PORTD_INT0_vect){

if (portd_int0_callback) {

portd_int0_callback();

}

}

 

 

code for further processing of EG

Josh

Last Edited: Thu. Jul 11, 2019 - 03:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

Good to see you ignored previous comments I made. Ho Hum.

 k------------------twi master enabled

'k' handling itself does nothing more than print \r\n. I presume that when the call is made into the unseen tcs_init() that it's in there it prints "twi master enabled" (BTW can you really read orange on white??) 

  !------------------- c

Sorry to be pedantic but it is 'C' not 'c' - details like this DO matter.

EG----------------- 30K

We can see the processing of 'E':

case 'E'//Experiment options

experiment_handler(getchar());

break;

 

But where is the code for experiment_handler(). If the further processing of 'G' after 'E' is failing then surely it's within the experiment_handler() code you have not shown?

 

BTW your code is a total mess - apart from the bad choice of colour the indentation is all over the place so it is very hard to follow the sequence of operation.  If you use Atmel Studio 7 then on the Edit menu is "Edit-Advanced-Format Document". Suggest you use that. It results in:

/*
* main.c
*
* Created: 29/09/2012 2:13:52 AM
* Author: mdryden
*/

#include "experiment.h"
#include "asf.h"
#include "wdt.h"
#include "settings.h"
#include "tcs.h"
#include <string.h>
#include <math.h>
#include <stdint.h>

//Internal function declarations
void command_handler(char command);

void command_handler(char command){
	/**
	* Deals with commands over USB
	*
	* Calls functions in
	* @param command Command character input.
	*/
	
	switch (command){
		case 'E': //Experiment options
		experiment_handler(getchar());
		break;
		case 'S': //Settings options
		settings_handler(getchar());
		break;
		case 'T': ;
		uint16_t tcs_data[] = {0,0,0,0};
		if (settings.settings.tcs_enabled == 0){
			printf("T-1.-1.-1.-1\n");
		}
		else {
			tcs_readvalues(tcs_data);
			printf("#INFO: TCS—%u %u %u %u\n", tcs_data[0], tcs_data[1], tcs_data[2], tcs_data[3]);
			printf("T%u.%u.%u.%u\n", tcs_data[0], tcs_data[1], tcs_data[2], tcs_data[3]);
		}
		break;
		
		case 'V': //check version
		#define STRING2(x) #x
		#define STRING(x) STRING2(x)
		#pragma message "GIT_COMMIT = " STRING(GIT_COMMIT)
		printf("V%u.%u.%u-%s\n", BOARD_VER_MAJOR, BOARD_VER_MINOR, BOARD_VER_MICRO, GIT_COMMIT);
		break;
		
		default:
		printf("#ERR: Command %c not recognized\n", command);
		return;
	}
	printf("no\n");
	return;
}

int main(void){
	
	board_init();
	pot_init();
	pmic_init();
	
	irq_initialize_vectors();
	cpu_irq_enable();
	sleepmgr_init();
	sysclk_init(); //Disables ALL peripheral clocks D:
	rtc_init();
	sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_EVSYS);
	
	pmic_set_scheduling(PMIC_SCH_ROUND_ROBIN);
	
	delay_ms(500);
	
	stdio_usb_init();
	stdio_usb_enable();
	
	ads1255_init_pins();
	ads1255_init_module();
	
	PORTD.INT0MASK = PIN5_bm;
	PORTD.INT1MASK = PIN5_bm;
	PORTD.INTCTRL = PORT_INT0LVL_OFF_gc | PORT_INT1LVL_OFF_gc;
	
	max5443_init_pins();
	max5443_init_module();
	
	ads1255_wakeup();
	ads1255_rdatac();
	ads1255_standby();
	ads1255_setup(ADS_BUFF_ON,ADS_DR_60,ADS_PGA_2);
	autogain_enable = 0;
	g_gain = POT_GAIN_30k;
	pot_set_gain();
	settings_read_eeprom();
	
	//  Wait for application connection - Get 'c', reply '#', get 'k'
	while(1){
		while(getchar() != 'c');
		putchar('#');
		while(getchar() != 'k');
		printf("\n\r");
		break;
	}
	
	tcs_init();
	
	program_loop:
	while(getchar() != '!');
	printf ("C\n");
	command_handler(getchar());
	goto program_loop;
}

I hope you, like me, find that MUCH easier to read/follow?

 

@clawson ididn't ignore your advice. i didn't write the code from scratch that i'll be able to make it easy to read. i copied it from vscode to send here and as such the reason for the coloring. I know its small "c" and not capital, my bad. and i don't know what you mean by  "I hope you, like me, find that MUCH easier to read/follow?" i sent in the code because you requested to see it. Didn't send it to punish anyone (incase its too long). if it was felt as that way, am deeply sorry. not my intention to offend anyone of the gurus here. please kindly assist me as am really learning alot from you guys 

Josh

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

raven231996 wrote:

/*

* main.c

*

* Created: 29/09/2012 2:13:52 AM

* Author: mdryden

*/

 

#include "experiment.h"

#include "asf.h"

#include "wdt.h"

#include "settings.h"

#include "tcs.h"

#include <string.h>

#include <math.h>

#include <stdint.h>

 

//Internal function declarations

void command_handler(char command);

 

void command_handler(char command){

    /**

     * Deals with commands over USB

     *

     * Calls functions in

     * @param command Command character input.

     */

 

    switch (command){

case 'E': //Experiment options

experiment_handler(getchar());

break;

case 'S': //Settings options

settings_handler(getchar());

break;

case 'T': ;

uint16_t tcs_data[] = {0,0,0,0};

if (settings.settings.tcs_enabled == 0){

printf("T-1.-1.-1.-1\n");

}

else {

tcs_readvalues(tcs_data);

printf("#INFO: TCS—%u %u %u %u\n", tcs_data[0], tcs_data[1], tcs_data[2], tcs_data[3]);

printf("T%u.%u.%u.%u\n", tcs_data[0], tcs_data[1], tcs_data[2], tcs_data[3]);

}

break;

 

        case 'V': //check version

#define STRING2(x) #x

#define STRING(x) STRING2(x)

#pragma message "GIT_COMMIT = " STRING(GIT_COMMIT)

printf("V%u.%u.%u-%s\n", BOARD_VER_MAJOR, BOARD_VER_MINOR, BOARD_VER_MICRO, GIT_COMMIT);

            break;

        

        default:

            printf("#ERR: Command %c not recognized\n", command);

            return;

    }

    printf("no\n");

    return;

}

 

int main(void){

    

    board_init();

    pot_init();

    pmic_init();

    

    irq_initialize_vectors();

    cpu_irq_enable();

    sleepmgr_init();

    sysclk_init(); //Disables ALL peripheral clocks D:

    rtc_init();

    sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_EVSYS);

    

    pmic_set_scheduling(PMIC_SCH_ROUND_ROBIN);

    

    delay_ms(500);

    

    stdio_usb_init();

    stdio_usb_enable();

    

    ads1255_init_pins();

    ads1255_init_module();

 

    PORTD.INT0MASK = PIN5_bm;

    PORTD.INT1MASK = PIN5_bm;

    PORTD.INTCTRL = PORT_INT0LVL_OFF_gc | PORT_INT1LVL_OFF_gc;

    

    max5443_init_pins();

    max5443_init_module();

    

    ads1255_wakeup();

    ads1255_rdatac();

    ads1255_standby();

ads1255_setup(ADS_BUFF_ON,ADS_DR_60,ADS_PGA_2);

autogain_enable = 0;

g_gain = POT_GAIN_30k;

pot_set_gain();

settings_read_eeprom();

 

    //  Wait for application connection - Get 'c', reply '#', get 'k'

    while(1){

        while(getchar() != 'c');

        putchar('#');

        while(getchar() != 'k');

        printf("\n\r");

        break;

    }

 

    tcs_init();

    

    program_loop:

        while(getchar() != '!');

        printf ("C\n");

        command_handler(getchar());

    goto program_loop;

}

 

 

 

the intention is;

 i send via pc------microcontroller response

           c------------------#

           k------------------twi master enabled

           !------------------- c

           EG----------------- 30K

 

but instead i have to send ! again before the 30k appears on the terminal. NOTE: I BOLDED THE 30K COMMAND LINE IN THE CODE ABOVE SO YOU CAN EASILY TRACE IT

 

 

 

 

 

how can i get 30k appear on the terminal without me sending ! again

Josh

Pages