Wednesday, March 25, 2015

CMake: Always running the post-build step

As the name suggests, the POST_BUILD option in CMake's add_custom_command() runs after building is complete and as a consequence, if the project target does not need to be re-built (as it has no changes), the post-build step will not be run. However, in some projects you may want to always run the post-build step; for example if you need to copy module libraries (i.e. which do not depend on the main project target but have been modified) to the main target's output directory so the application can run. Luckily there is a simple workaround to achieve this:

1. Add an empty header file (.h) to your project with the following name: always_do_post_build.h
2. Ensure that this file is monitored by CMake by including it in add_executable():
add_executable(${CMAKE_PROJECT_NAME}
  ${SOURCE_FILES}
  ${HEADER_FILES}
  always_do_post_build.h
)
3. Also add the following to your CMakeLists.txt file:
add_custom_target(ALWAYS_DO_POST_BUILD
  COMMAND ${CMAKE_COMMAND} -E echo touching always_do_post_build.h
  COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_SOURCE_DIR}/always_do_post_build.h
)
add_dependencies(${CMAKE_PROJECT_NAME} ALWAYS_DO_POST_BUILD)

How does it work?

An extra dummy target (ALWAYS_DO_POST_BUILD) is created which depends on the main project target (CMAKE_PROJECT_NAME). Due to this dependency, the dummy target will run before the main project target and ensures that the always_do_post_build.h file (which is monitored by the main project target) is always "out of date" via the touch command. This will trigger the main project target to perform a re-build and thus run the post-build step as required. NOTE: A header file (.h) is used so that no code is compiled in the process.

Update (August 16, 2015)

An alternative to the above is to simply add the following to each module library's CMakeLists.txt file:


# Post-Build Step: Create required directory
add_custom_command(TARGET ${LIBRARY_NAME} POST_BUILD
  COMMAND ${CMAKE_COMMAND} -E make_directory
  $<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>/path/to/where/module/should/be
  COMMENT "Creating directory: " $<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>/path/to/where/module/should/be
)
# Post-Build Step: Copy library DLL to runtime directory
add_custom_command(TARGET ${LIBRARY_NAME} POST_BUILD
  COMMAND ${CMAKE_COMMAND} -E copy_if_different
  $<TARGET_FILE:${LIBRARY_NAME}>
  $<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>/path/to/where/module/should/be
  COMMENT "Copying file to Runtime directory: " $<TARGET_FILE:${LIBRARY_NAME}>
)

Friday, March 13, 2015

XMEGA 32E5: One-shot pulse using the XCL module

As the XCL (short for XMEGA Custom Logic) module found in the new XMEGA E series is a completely new peripheral not found in any previous Atmel chips, documentation and example code is fairly scarce. After taking the plunge and attempting to implement a one-shot pulse as described in AT01084 (Section 4.8.4), I found that the latest Atmel Software Framework (v3.22.0) has forgotten this particular XCL timer/counter operating mode! Perhaps it just isn't as popular as the other modes? But it's incredibly useful if you need a simple way to send a pulse to turn on an external device such as a PC (without using software delays or interrupts in your code).

Anyway, to be more specific on the omission: ASF is missing the One-Shot PWM mode enumeration in the xcl_tc_mode_t enum type (bug report).

Here are the modes listed in AT01084 (Section 4.8):

Not a big deal - we just need to manually specify the MODE mask (0x03) when calling the xcl_tc_mode() ASF function. After that, it's smooth sailing!

In the below example, we will output a logic-low pulse with a fixed duration (after a certain optional delay) on Port D Pin 2.

A few notes before we get into it:
  • With a 2 MHz peripheral clock:
    • 16-bit XCL timer/counter allows a pulse length of up to ~33.5 seconds.
    • 8-bit XCL timer/counter allows a pulse length of up to ~131 milliseconds.
  • Pulses can be output on either PD2 and/or PD3:
    • 16-bit XCL timer/counter: the pulse can be outputted on PD2 only.
    • 8-bit XCL timer/counter: in this case, as we have two separate timers, two independent pulses with different timing characteristics can be outputted on PD2 and PD3.

 

Example:

 

1. Initialize the XCL module and configure to output a one-shot pulse:
xcl_enable(XCL_SYNCHRONOUS);
xcl_port(PD);
xcl_tc_type(TC16);
xcl_tc_mode(0x03);  // MODE[1:0] = 2b'11 : One-shot PWM mode
xcl_tc_source_clock(DIV1024); // Starts timer

2. Set OC0 (PD2) as an output pin and also set inverted so we get a low pulse:
PORTD.DIR = 0x04;
PORTD.PIN2CTRL = PORT_INVEN_bm | PORT_OPC_TOTEM_gc | PORT_ISC_BOTHEDGES_gc;

3. Function to generate the one-shot pulse:
void pulse(uint16_t wait_ms, uint16_t pulse_len_ms)
{ 
    uint16_t _wait_ms = wait_ms / ((1024.0 / F_CPU) * 1000);
    uint16_t _pulse_len_ms = pulse_len_ms / ((1024.0 / F_CPU) * 1000);
   
    // Stop any currently in progress pulses
    xcl_disable_oc0();
    // Start at CNT
    xcl_tc16_set_count(_wait_ms + _pulse_len_ms);
    // Pulse begins at CMP and ends at BOT
    xcl_tc16_set_compare(_pulse_len_ms);
    // Start timer
    xcl_enable_oc0();
    xcl_tc_restart(RESTART_TIMER0);
}

4. Now we simply call the above function with our desired parameters:
pulse(500, 1000); // Delay 500 ms then output 1000 ms pulse on OC0

5. Voila! No interrupts or software delays needed! Easy!